###### tags: `SILENT`
# Silent Relayers
## Overview
Silent relayer to process Silent protocol transactions
## Background
Silent relayer is needed to process all transactions for multiple Silent pools/contracts through single entity, which can obsure and make users transactions private and also optimise UX/fees as users will only need to do single action like erc20.approve(contract/relayer, amount) once and send ETH fees to relayer once. Then users can make multiple requests through relayer, which can execute transactions many times without any additional on-chain transactions.
## Relayers
For now Relayer is a generalized separate module, which anyone who wants to be a relayer to process users transactions, earn fees and rewards, can boostrap. To support a particular smart contract or Silent protocol contract, for which Relayer will execute transactions, ABI (smart contract interface) needs to be added into ABIs list in relayer code and generate interface in the Relayer based on it. Then relayer will be to process transactions data in format {contractAddress, contractMethod, methodArguments}.
## Flows
 
## Architecture
### Overview
Overall, Silent Relayer is based on pub-sub jobs processing model, which is based on Nest.js framework. Users send (publish) JSON-RPC requests to relayer through UI or scripts for transactions being executed. Relayer puts them in the queue and processes them one by one, parses data and sends to respective smart contracts to be executed on-chain. Validates transactions requests, stored them in Redis to be able to execute them later and takes them as a job later for execution.
### Technical Components
**ABI**: JSON ABI for working with smart contracts
**Artifacts**: The generated file contains typed contract instances
### Config:
**Bull Config**, `bull.config.ts` bull service settings
**Configuration**, configuration.ts global application configuration
`txManager.config.ts` txManager service settings
### Constants
**Contracts**, `contracts.ts` addresses of contracts and rps
**Variables**, `variables.ts` various variables to make things easier
### Modules
**Controller**, `controller.ts` Controller file that will contain all the application routes
**Module**, `module.ts` The module file essentially bundles all the controllers and providers of your application together.
**Service**, `service.ts` The service will include methods that will perform a certain operation.
**Main**, `main.ts` The entry file of the application will take in your module bundle and create an app instance using the NestFactory provided by Nest.
### Services
**GasPrice Service**, `gas-price.ts` updates gas prices on each transaction request to calcualte fees correctly
**Provider Service**, `provider.ts` add-on for working with `ethers.js`, which takes chain data (can support any configured EVM chain) and makes on-chain actions, such as sending transactions.
### Processors
**Transactions Processor**, `transaction.processor.ts` processes transactions jobs, taked from the queue, with a general format {contractAddress: address, method: string, args: []}, where method is contract method being executed and args are arguments of executed method
### Utilities
**Types**: types for the application
**Utilities**: helpers functions
## Relayer Incentive Mechanism
Relayers acquire portion of EBB tokens required to issue an NFT, representing amounts, which is set for their EBB pool, in Silent NFTMinting contract. Then they can be registered as a relayer in NodeRegistry by the protocol, where they need to stake that NFT to earn rewards. Each NFT has set SWAP token points, earned by relayers each second and it is multiplied by transactions they have processed in their corresponding EBB pools. That is nullified once they periodically claim those SWAP token rewards.
Relayers then can take their SWAP tokens and stake them on RedeemTreasury contract, which allows them to earn shared protocol ETH fees and claim them once during each epoch.
## DISCLAIMER
Code and architecture are based on Tornado Pool Relayer implementation, but has a different integration with smart contracts and chains to fit Silent Protocol, a bit different transactions proccessing model, different smart contracts interfaces, transactions requests, etc.
# EBB Silent transactions through payload
## Approach
In general, user signs **{arguments, nonce}** on UI side with his private key, for **depositFor** function in particular:
**arguments{publicKeys, ephermalPublicKeys, secret, amount}**
Process is the same as if he would create normal signature for data with his private key through Metamask or whatever. Same is done on scripts side (there is deposit-for script command).
Nonces will be stored for users in the EBB contract to verify signature so that relayer cannot use transaction twice and we will increment nonce on each deposit (nonces[user]++).
User would still need to do approve for ERC-20 on amount for relayer to spend, send gas fees (plus ETH amount if its ETH deposit) to relayer before that. He can only approve once large ERC-20 amount or send ETH fees/funds once to relayer.
ETH smart contract signature in format **{v, r, s}**
**depositFor(publicKeys, ephermalPublicKeys, secret, amount, requester, v, r, s)**
It will check signature, increment nonce, process all fees and then do same process as normal deposit function, but it will also be executed by relayer. Calldata for execution will be sent through EBB relayer.
# Relayer (Tornado implementation)
Implementation consists of express.js server with Redis database, which sets up queue of tasks and events, including withdrawals and withdrawals mining, updating mining tree accounts state and processors to complete tasks by workers.
**Tornado cash relayer implementation fits us except few details (discussable):**
1. It generates MerkleTree to keep accounts state and mining rewards, which we can store simply as accounts => balances in database like Redis, which Tornado Relayer uses.
2. We don't have mining rewards, which is used to generate multiple equal amounts transactions, we will cut it off
**Nice implementation features:**
1. Master-Slave pattern, which supports global queue of tasks and then parallize tasks completion to workers
2. Redis as the database
3. Express.js server
**What needs to be added:**
1. EBB contracts methods processing: deposits, withdrawals, rings
2. EBB contracts events processing
3. Users IP addressses storage (can be hashed or encrypted)
###### tags: `SILENT`
# Silent Crypto
[toc]
## Cryptographic Primitives
### Notations
### Hash Functions
#### SHA256
#### Poseidon
#### MiMC
### Elliptic Curves
#### Baby Jubjub
[*Baby Jubjub*](https://github.com/barryWhiteHat/baby_jubjub), a twisted Edwards curve defined over the finite field $F_q$ which can be used inside any zk-SNARK circuit, allowing for the implementation of cryptographic primitives that make use of elliptic curves.
Let $F_q$ be the prime finite field with `q` elements, where
```
q = 21888242871839275222246405745257275088548364400416034343698204186575808495617
```
Let $E$ be the twisted Edwards elliptic curve defined over $F_q$ described by equation
```
ax^2 + y^2 = 1 + dx^2y^2
```
with parameters
```
a = 168700
d = 168696
```
Baby Jubjub is the curve $E(F_q)$, that is, the subgroup of $F_q$-rational points of $E$.
Baby Jubjub has order
```
n = 21888242871839275222246405745257275088614511777268538073601725287587578984328
```
which factors in
```
n = h x l
```
where
```
h = 8
l = 2736030358979909402780800718157159386076813972158567259200215660948447373041
```
The parameter $h$ is called *cofactor* and $l$ is a prime number of 251 bits.
BabyJubjub curve operations are implemented in [Silent Github repo](https://github.com/projecteuanthe/elara-crypto/blob/main/src/utils.ts) as follows:
```typescript=
**
* Computes exponent mul Base8
* @param exponent exponent
* @returns Point
*/
function ecMulBase(exponent: Scalar): Point {
return babyjub.mulPointEscalar(babyjub.Base8, exponent);
}
/**
* Compute scalar point multiplication
* @param point BabyJub point
* @param exponent exponent
* @returns Multiplication result point
*/
function ecMul(point: Point, exponent: Scalar): Point {
return babyjub.mulPointEscalar(point, exponent);
}
/**
* Compute point addition
* @param point1 First BabyJub point
* @param point2 Second BabyJub point
* @returns Addition result point
*/
function ecAdd(point1: Point, point2: Point): Point {
return babyjub.addPoint(point1, point2);
}
function ecSub(point1: Point, point2: Point): Point {
const negPoint2: Point = [point2[0], babyjub.F.neg(point2[1])];
return ecAdd(point1, negPoint2);
}
function derivePrivateKey(seed: Uint8Array) : Scalar {
const hash = sha256(seed);
hash[0] &= 0xF8;
hash[31] &= 0x7F;
hash[31] |= 0x40;
const s = Scalar.fromRprLE(hash, 0, 32);
return Scalar.shr(s, 3);
}
/**
* Samples a private key as a random scalar for BabyJub curve
* @returns Private key
*/
function genPrivateKey() : Scalar {
const buff = getRandomBytesSync(32);
return derivePrivateKey(buff);
}
/**
* Deterministicly computes a public key from a private key
* @param privateKey Exponent to Base8 on BabyJub curve
* @returns Public key
*/
function genPublicKey(privateKey: Scalar): Point {
return ecMulBase(privateKey);
}
/**
* Genereate a key-pair of `privateKey` and the corresponding `publicKey` on BabyJub curve
* @returns Key-pair
*/
function genKeyPair(): KeyPair {
const privateKey = genPrivateKey();
const publicKey = genPublicKey(privateKey);
return {
privateKey, publicKey,
};
}
```
### Re-randomizable Public-key Encryption
:::info
:information_source: The following definition is coherent with [Silent's account implementation](https://github.com/projecteuanthe/elara-crypto/blob/9c2383b805f096b7392e37aac1713e31c6db18be/src/account.ts).
:::
#### ElGamal Public-key Encryption
- _Setup_ : a group $\mathbb{G}$ of a prime order $q$ with a generator $G$, set ${\sf pp_{eg}} \gets \{\mathbb{G}, q, G\}$ as ElGamal public parameters.
Silent utilizies the additive group of [Baby JubJub](https://hackmd.io/QjU5VAZoTtCOEcy2A99P1w?#Baby-Jubjub) from [Circom 2.0](https://hackmd.io/QjU5VAZoTtCOEcy2A99P1w?#Circom-20) as $\mathbb{G}$ for ElGamal public-key encryption scheme:
```typescript=
const { babyjub, poseidon } = require('circomlibjs');
```
- _KeyGen_ : $({\sf sk},{\sf pk}) \gets ({\sf pp_{eg}})$ - generate a random scalar $y \in \mathbb{Z}_q$, set it as the private key ${\sf sk} \gets y$ and compute $Y \gets yG$ set it as the corresponding public key ${\sf pk} \gets Y$.
```typescript=
function genKeyPair(): KeyPair {
const privateKey = genPrivateKey();
const publicKey = genPublicKey(privateKey);
return {
privateKey, publicKey,
};
}
```
- _Encrypt_ : $(C_1,C_2) \gets ({\sf pk},m)$ -
1. generate a random scalar $r \in \mathbb{Z}_q$
2. compute
1. $C_1 \gets rG$
2. $C_2 \gets mG + rY$
3. output $(C_1,C_2)$
```typescript=
static encrypt(balance: Scalar, publicKey: Point) :ElGamalCiphertext {
const r = genPrivateKey();
const C1 = ecMulBase(r);
const C2 = ecAdd(ecMulBase(balance), ecMul(publicKey, r));
return { C1, C2 };
}
```
- _Decrypt_ : $m \gets ({\sf sk}, (C_1,C_2))$ -
1. compute
1. $S \gets yC_1$
2. $mG \gets C_2 - S$
2. output m
The nuance in decryption: running the standard decryption gives you $mG$ and recovering $𝑚$ requires one to solve the discrete log for $mG$. As long as $𝑚$ is small, this can be done algorithmically or with a lookup table when applicable (This phase is omitted in the following code snippet, since we don't need to recover $m$.).
```typescript=
getBalance(ciphertext: ElGamalCiphertext): Point {
return ecSub(ciphertext.C2, ecMul(ciphertext.C1, this.privateKey));
}
```
#### ElGamal Re-randomization
- _Rerandomize_ : $(D_1,D_2) \gets ({\sf pk},(C_1,C_2))$ -
1. generate a random scalar $r' \in \mathbb{Z}_q$
2. compute
1. $D_1 \gets C_1 + r'G$
2. $D_2 \gets C_2 + r'Y$
3. output $(D_1,D_2)$
```typescript=
static randomize(ciphertext: ElGamalCiphertext, publicKey: Point, r: Scalar): ElGamalCiphertext {
const C1 = ecAdd(ciphertext.C1, ecMulBase(r));
const C2 = ecAdd(ciphertext.C2, ecMul(publicKey, r));
return { C1, C2 };
}
}
```
Note that, since
$D_1 = rG + r'G = (r+r')G$ and
$D_2 = C_2 + r'Y = mG + (r+r')Y$,
$(D_1,D_2)$ is the ciphertext of the message $m$ under the random scalar $r+r'$.
#### Additively Homomorphic ElGamal
Suppose that we have ElGamal ciphertext $(C_1',C_2') \gets ({\sf pk}, m_1)$ for message $m_1$ and $(C_1'',C_2'') \gets ({\sf pk}, m_2)$ for message $m_2$ with some random scalar $r'$ ($r''$, respectively). Since we have,
$C_1'+C_1''= r'G + r''G = (r'+r'')G$ and
$C_2'+C_2''=m_1G + r'Y + m_2G + r''Y= (m_1+m_2)G + (r'+r'')Y$,
by setting
$C_1 \gets C_1'+C_1''$ and
$C_2 \gets C_2'+C_2''$,
we get ElGamal ciphertext $(C_1,C_2)$ for the message $m_1+m_2$ and random scalar $r'+r''$, without actually decrypting $(C_1',C_2')$ and $(C_1'',C_2'')$, and then encrypting $m_1+m_2$ with $r'+r''$.
### Signature Schemes
#### Schnorr Signature
The Schnorr signature scheme [Sch91](https://doi.org/10.1007/BF00196725) given below assumes [BDL+11](https://doi.org/10.1007/BF00196725)'s key prefixed version.
- _Setup_ : a group $\mathbb{G}$ of a prime order $q$ with a generator $G$ and a hash function ${\sf H}$, set ${\sf pp_{sc}} \gets \{\mathbb{G}, q, G\}$ as Schnorr public parameters.
- _KeyGen_ : $({\sf sk},{\sf pk}) \gets ({\sf pp_{sc}})$ - generate a random scalar $x \in \mathbb{Z}_q$, set it as the private key ${\sf sk} \gets x$ and compute $X \gets xG$ set it as the corresponding public key ${\sf pk} \gets X$.
- _Sign_ : $\sigma \gets ({\sf sk},m)$ -
1. generate a random scalar $r \in \mathbb{Z}_q$
2. compute
1. $R \gets rG$
2. $c = {\sf H}(X,R,m)$
3. $s = r + cx$
3. output the signature $\sigma \gets (R,s)$ on message $m$.
- _Verify_ : $\{True,False\} \gets ({\sf pk},m, (R,s))$ -
1. compute
1. $c = {\sf H}(X,R,m)$
2. $sG$
3. output $True$ if the equation $sG = R+cX$ holds, or $False$, otherwise.
#### EdDSA Signature
#### MuSig: Schnorr-based Multi-Signature
A multi-signature scheme is a combination of a signing and verification algorithm, where multiple signers (each with their own private/public key) jointly sign a single message, resulting in a single signature. This single signature can then be verified by anyone who also knows the message and the public keys of the signers. [MuSig](https://eprint.iacr.org/2018/068.pdf) is a multi-signature that supports key-aggregation scheme based on Schnorr Signatures. Key aggregation refers to multi-signatures that look like a single-key signature, but with respect to an aggregated public key that is a function of only the participants’ public keys. Verifiers can run the signature verification function with the aggregated public key, without knowing the original participants’ public keys. Please refer to [GS18](https://www.politesi.polimi.it/bitstream/10589/144372/1/main.pdf) for more details on Schnorr signatures.
- _Setup_ : a group $\mathbb{G}$ of a prime order $q$ with a generator $G$ and three hash functions ${\sf H}_{c}, {\sf H}_{a}, {\sf H}_{s}$, set ${\sf pp_{ms}} \gets \{\mathbb{G}, q, G\}$ as MuSig public parameters.
Here details of [MuSig](https://eprint.iacr.org/2018/068.pdf) algorithm is given. Apart from this, there are other schemes as well, such as
- 2020 - [MuSin-DN](https://eprint.iacr.org/2020/1057.pdf)
- 2021 - [MuSig2](https://eprint.iacr.org/2020/1261.pdf)

- 2022 - [Simple Three-Round Multiparty Schnorr Signing
with Full Simulatability](https://eprint.iacr.org/2022/374.pdf)
:::info
:information_source: Even if [MuSig](https://eprint.iacr.org/2018/068.pdf) states three hash functions, some implementations utilize only one hash function instead of three.
Various implemantations:
- **[Matter Labs](https://github.com/matter-labs/schnorr-musig)**'s Rust implementation of MuSig scheme that contains generated wasm code and a typescript-example.
- **[Jonas Nick](https://github.com/jonasnick/secp256k1-zkp/tree/bulletproof-musig-dn-benches/src)**'s Github repo for Bulletproofs and MuSig-DN.
:::
- _KeyGen_ : $({\sf sk}_i,{\sf pk}_i) \gets ({\sf pp_{ms}})$ - for each signer ($1\leq i \leq n$), generate a random scalar $x_i \in \mathbb{Z}_q$, set her private key as ${\sf sk_i} \gets x_i$ and compute $X_i \gets x_iG$ set it as the corresponding public key ${\sf pk}_i \gets X_i$.
- _Sign_ : $\sigma \gets (\{{\sf sk}_1, {\sf sk}_2, \ldots, {\sf sk}_n\},m)$ - Each signer follows the steps given below as if she owns the key-pair $({\sf sk}_1 \gets x_1, {\sf pk}_1 \gets xG)$.
1. Signer receives all public keys and sets $L \gets \{ {\sf pk}_1, {\sf pk}_2, \ldots, {\sf pk}_n\}$ and computes aggregated public key $\tilde{X}$:
$\tilde{X} \gets \sum_{i=1}^{n}a_iX_i$ where $a_i \gets {\sf H}_a(L,X_i)$
2. Signer generates a random scalar $r_1 \gets \mathbb{Z}_q$ and computes $R_1 \gets r_1G$, sends her computed commitment $t_1 \gets {\sf H}_c(R_1)$ to all other cosigners.
3. Upon receiving cosigners' commitments $t_2, t_3, \ldots, t_n$, signer reveals his commitment $R_1$ to cosigners.
4. Signer receives commitments $R_2, R_3, \ldots, R_n$ and checks that $t_i = {\sf H}_c(R_i)$ for all $i \in \{2,3, \ldots,n\}$ and computes
1. $R \gets \sum_{i=1}^{n}R_i$,
2. $c \gets {\sf H}_{s}(\tilde{X},R,m)$,
3. $s_1 \gets r_1 + ca_1x_1$.
5. Signer reveals $s_1$ to all cosigners.
6. Upon receiving cosigners' $s_2, s_3, \ldots, s_n$, she can finally compute $s \gets \sum_{i=1}^{n}s_i$
7. the signature is $\sigma \gets (R,s)$.
- _Verify_ : $\{True,False\} \gets (L,m, (R,s))$ -
1. compute
1. $a_i \gets {\sf H}_a(L,X_i)$ for $i \in \{1,2, \ldots,n\}$,
2. $\tilde{X} \gets \sum_{i=1}^{n}a_iX_i$,
3. $c \gets {\sf H}_{s}(\tilde{X},R,m)$,
4. $sG$
3. output $True$ if the equation
$sG = R+\sum_{i=1}^{n} c a_iX_i = R + c\tilde{X}$
holds, or $False$, otherwise.
#### MuSig2: Schnorr-based Multi-Signature
### Commitments
## User Keys, Addresses and Accounts
Silent keeps its user's balances in account-based model. A user account is a tuple ${\sf acc} \gets ({\sf pk}, (C_1,C_2))$.
### Account Key Generation
Silent account keys are generated and managed according to BIP39 and BIP42.
When a user $A$ with Ethereum key pair $(priv_{Eth,A}, pub_{Eth,A}, addr_{Eth,A})$ wants to generate a Silent account,
1. the user computes a signature $\sigma_A$ on a given message with her private key $priv_{Eth,A}$ using his Metamask wallet.
2. Then this signature is used as a seed to derive a mnemonic phrase $mnemonic_A$.
3. Using $mnemonic_A$, $masterSeed_A$ is generated.
4. Then a private key $priv_A$ is generated using $masterSeed_A$.
Since the private keys are generated from user's signature which is computed by a deterministic signature algorithm, a Silent user does not need to install a new wallet for Silent and can get access to his account with only his Metamask wallet. In addition to this, user can store his mnemonic phrase and get access to his Silent account using this mnemonic.
> If a user wants to generate a different Silent account, the user needs to create a different Ethereum address on Metamask and initiate account generation process with the new address since private key generation is done deterministically.
### Accounts
Silent keeps its user's account as a tuple ${\sf acc} \gets ({\sf pk}, (C_1,C_2))$ where
- ${\sf pk}$ is the user's ElGamal public key corresponding to the private key ${\sf sk}$, and
- $(C_1,C_2)$ is the ElGamal ciphertext of the account balance $b$;
$C_1 \gets rG$ and $C_2 \gets mG + rX$, i.e. $r \in \mathbb{Z}_q$ is random scalar and $X \gets xG$ is the user's public key ${\sf pk}$.
Typescript implementation and Circom 2.0 account template for user account is included in [here](https://github.com/projecteuanthe/elara-crypto/blob/main/src/account.ts) and [here](https://github.com/projecteuanthe/elara-crypto/blob/9c2383b805f096b7392e37aac1713e31c6db18be/circuits/templates/account.circom), respectively.
> update the github links after Github repo reformation!
| Variable |Type |Size | Description |
|:---------|:-------|:--------|:----------------------------------|
|`EGPrivKey` |Scalar |254bits | the private key, ${\sf sk} \gets x$, i.e. $x \in \mathbb{Z}_q$|
|`EGPubKey` |Point |256bits| public key: BabyJubjub curve point, ${\sf pk} \gets xG$|
|`balance` |Scalar |254bits | Account balance, $b \in \mathbb{Z}_q$ with $b \leq a_{\sf max}$|
|`EGCtext`|(Point, Point)|2x 256bits| Account state as ElGamal ciphertext $(C_1,C_2)$ |
### Stealth Address
When a user wants to interact with an adapter and wants to generate a stealth address,
1. the user computes a signature $\sigma_A$ on a given message with her private key $priv_{Eth,A}$ using his Metamask wallet.
2. Then this signature and adapterId is used as a seed to derive a mnemonic phrase $mnemonic_A$.
3. Using $mnemonic_A$, $masterSeed_A$ is generated.
4. Then a private key $priv_{A,adapterId}$ is generated using $masterSeed_A$.
> [name=znur] is 2 okey?
### Compliance
In the transfer and withdraw, transaction details are encrypted for compliance. Suppose that sender's key pair is $s_s,P_s$ and DAO's key pair is $s_{DAO}, P_{DAO}$. Encryption for the compliance is as follows.
1. Get a number $r$ in order to derive a different shared key for each transaction and compute ephemeral public key $R = r P_s$.
2. Compute sharedSecret = poseidon$((rs_s)P_{DAO})$.
3. Let txDetails = $[P_s[0], P_s[1], P_{DAO}[0], P_{DAO}[1], amount]$.
4. $iv$ = mimc7.hash(rand(), 91).
5. EncryptedTxDetails = []
6. for $0 \leq i < 5$:
$\quad$ EncryptedTxDetails[$i$] = txDetails[$i$] + mimc7.hash($iv+i+$sharedSecret, 91)
7. return (R, iv, EncryptedTxDetails).
When DAO wants to reveal transactions belonging to a particular address, they need to find the transactions that the address takes part as sender or receiver. Since transfer and withdraw uses anonymity sets, it is not possible to identify this transactions exactly. Instead, DAO can find the transactions that the anonymity set contains the address. Then, for each transaction, they do the following steps.
1. compute sharedSecret = poseidon$(s_{DAO}R)$.
2. for $0 \leq i < 5$:
$\quad$ TxDetails[$i$] = EncryptedTxDetails[$i$] - mimc7.hash($iv+i+$sharedSecret, 91)
3. sender = [TxDetails[0], TxDetails[1]]
receiver = [TxDetails[2], TxDetails[3]]
amount = TxDetails[5]
This process reveals not only the transactions that belong to the particular user but details of all of the transactions that the particular address is involved in the anonymity set.
<!--Please note that, in order to compute the sharedSecret that is used to encrypt/decrypt transaction details, DAO needs to use their secret key. This can be done in two ways.
1. Secret sharing: Each member has a share of the secret key ($s_{DAO}$ in this case), and the secret key can be revealed if $t$ out of $m$ members participate, then this secret is used to compute $sharedSecret$. Downside of this is that the secret key is out after the process.
2. Threshold encryption: Each DAO member has a share of the secret and DAO has a single public key. Users of the Silent protocol can encrypt a message using DAO's public key. In order to decrypt, $t$ out of $m$ members need to participate and compute their partial decryption shares. sharedSecret is revealed after combining the shares. -->
NOTE: There is not a mechanism in place that prevents DAO from decrypting all of the transactions.
#### DAO Public Key Generation
Suppose that DAO has $n$ members. Now we describe a mechanism such that $k$ of them are able to decrypt messeges. It is assumed that $n \geq 2k-1$.
Let $C(m,r)$ denote a commitment to a message $m$ using a random $r$. Then, DAO public key is generated as follows:
1. Each party $P_i$ chooses random $x_i$ and computes $Q_i = x_iP$. Then $P_i$ chooses a random $r_i$ and broadcasts $C_i$.
2. When all parties broadcast their commetments, each $P_i$ opens its commitment $C_i$ and everybody knows $Q_i$.
3. The public key $P_{DAO} = \sum_{i=1}^n Q_i$.
At this point, all members know the public key however they can not find/use the secret key, $x = \sum_{i=1}^n x_i$, unlesss all of them participate in the process. Since we want $k$ of them to be able to use the secret key, each party $P_i$ is going to share their secrets in a way that $k$ parties are able to use $x_i$.
> [name=togobramble] we need to decide how this $n$ members would be selected. If we let any $k$ DAO member would form decryption set then with the Sybil attack, an attacker can pose as $k$ different entity and then decrypts messages. If this would be case, we need to let DAO as golden member for forming decryption set.
#### DAO Secret Key Share Generation
1. $P_i$ chooses a polynomial $f_i(x)$ of degree $k-1$ such that $f_i(0)=x_i$. Let $$f_i(x) = f_{i0} + f_{i1} x + \ldots + f_{i(k-1)} x^{k-1},$$ where $f_{i0} = x_i$.
2. $P_i$ computes $F_{ij}=f_{ij}P$ for $0 \leq j \leq k-1$ and broadcasts $\{F_{ij}\}_{1\leq j \leq k-1}$. Notice that $F_{i0} = Q_i$ is known before this process.
3. When all parties broadcast $F_{ij}$'s, $P_i$ does the following for each $1 \leq j \leq n$
3.1. evalutes $f_i$ at $j$, $s_{ij} = f_i(j)$, and sends $s_{ij}$ and a signature $\sigma_{ij}$ on $s_{ij}$ to $P_j$, secretly.
After this phase is completed, each party verifies that the other parties followed the protocol correctly.
1. $P_i$ verifies that the share $s_{ji}$ received from $P_j$ is consistent with the values broadcast by $P_j$ by checking $$s_{ji}P = \sum_{l=0}^{k-1} i^l F_{jl}.$$
2. If the above verification fails, $P_i$ broadcasts that an error is found, publishes $s_{ij}$ and $\sigma_{ij}$, and stops.
3. $P_i$ computes its share of $x$ as the sum of the shares $s_{ji}$ that $P_i$ received, $$s_i = \sum_{j=1}^n s_{ji}.$$
4. Finally, $P_i$ signs $P_{DAO}$.
#### DAO Decryption
For each transaction with ephemeral key $R$, each/some DAO member $P_i$ computes $w_i = s_iR$ and sends to Authority. After getting shares from $k$ members, denote the set as $S$, Authority
1. computes the lagrange coefficients $\lambda_i = \prod_{j\in S\i} \frac{i}{j-i}$.
2. computes $s_{DAO}R$ as $\sum_{i\in S} \lambda_i w_i$.
3. computes sharedSecret = poseidon$(s_{DAO}R)$.
4. for $0 \leq i < 5$:
$\quad$ TxDetails[$i$] = EncryptedTxDetails[$i$] - mimc7.hash($iv+i+$sharedSecret, 91)
5. sender = [TxDetails[0], TxDetails[1]]
receiver = [TxDetails[2], TxDetails[3]]
amount = TxDetails[5]
#### Proposal to Reveal Only Transactions of a Particular Account
Instead of having only one key, suppose that Silent users have two keys: spending key/compliance key (S,C). Spending key is the regular key that we had before and we will use compliance key only while encrypting transaction details.
Currently, the sender generates a random $r$, computes $R=rP$, uses $R$ to derive a shared secret, encrypts the transaction with the shared secret, and sends $R$ along with the transaction.
It works different for Transfer and Withdraw. Withdraw is simpler, so we start with it.
Suppose that we also compute $R' = H(rC_{sender}) + S_{sender}$, and add $R'$ among transaction values. Normally all transactions that include $(S_{sender},C_{sender})$ in the anonymity set are decrypted. Now, instead Authority is able to compute $R'' = H(c_{sender}R)G+S_{sender}$ and check if $R'' = R'$. In order for this to work, user needs to share its viewing key $c_{sender}$ with the authority.
For the transfer, there are two encryptions one is intended for the recipient and one for compliance. Compliance part is same as withdraw, so the authority is able to decide if it is sent by the particular address. While encrypting transaction details for the recipient, similarly, the sender now computes $R' = H(rC_{recipient}) + S_{recipient}$ and the authority is able to identify it it belongs to the particular address.
So, the authority is able to identify the transactions that a particular user takes part if that user shares its viewing key with the authority. It only requires keeping two addresses for the user in SC and one extra EC addition for the encryption/decryption.
This viewing key can also be splitted among DAO members instead of sharing it, they compute their corresponding parts, send it to the authority and the authority combines them to see if the transaction belongs to the user.
## Crypto Library
### [Types](https://github.com/projecteuanthe/elara-crypto/blob/main/src/types.ts)
Defines the types that are used throught the crypto library.
[BabyJubjub](#Baby-Jubjub) field element:
```
type Scalar = bigint
```
[BabyJubjub](#Baby-jubjub) elliptic curve point on $\mathbb{G}_1$:
```
type Point = [bigint, bigint]
```
[ElGamal](#ElGamal-Public-key-Encryption) key pair on BabyJubjub
```
interface KeyPair {
privateKey: Scalar, // x
publicKey: Point // Y = xG
}
```
[ElGamal](#ElGamal-Public-key-Encryption) ciphertext
```
interface ElGamalCiphertext{
C1: Point, // rG
C2: Point // mG+rY
}
```
[EdDSA Signature](#EdDSA-Signature)
```
interface SchnorrSignature{
R: Point,
s: Scalar
}
```
Aggregated public key and user's coefficient for [MuSig2](#MuSig2-Schnorr-based-Multi-Signature)
```
interface PublicKeyAgg{
aggPublicKey: Point,
musigCoefficient: Scalar
}
```
Partial signature to be aggregated into the final signature for [MuSig2](#MuSig2-Schnorr-based-Multi-Signature)
```
interface PartialSignature{
R: Point,
myPartialS: Scalar,
}
```
```
interface TransactionCiphertext{
iv: Scalar,
data: Scalar[]
}
```
```
interface TransactionDetails{
sender: Point,
recipient: Point,
amount: Scalar
}
```
### [Utils](https://github.com/projecteuanthe/elara-crypto/blob/main/src/utils.ts)
#### `ecMulBase`
- *Description*: Multiplies the base point with the given scalar
| Input | Type | Description |
| :-------- | :-------- | :-------- |
| `exponent` | Scalar | scalar |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Point | `exponent`$*\mathbb{G}$|
```
/**
* Computes exponent mul Base8
* @param exponent exponent
* @returns Point
*/
function ecMulBase(exponent: Scalar): Point
```
#### `ecMul`
- *Description*: Multiplies the given point with the given exponent and returns the result
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`point` | Point | point to multiply |
| `exponent` | Scalar | scalar |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Point | `exponent`$*$`point` |
```
/**
* Compute scalar point multiplication
* @param point BabyJub point
* @param exponent exponent
* @returns Multiplication result point
*/
function ecMul(point: Point, exponent: Scalar): Point
```
#### `ecAdd`
- *Description*: Adds given two points and returns the result
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`point1` | Point | point to add |
| `point2` | Point | point to add |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Point | `point1`+`point2` |
```
/**
* Compute point addition
* @param point1 First BabyJub point
* @param point2 Second BabyJub point
* @returns Addition result point
*/
function ecAdd(point1: Point, point2: Point): Point
```
#### `ecSub`
- *Description*: Substract the second point from the first point and returns the result
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`point1` | Point | point to substract from |
| `point2` | Point | point to be substracted |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Point | `point1`$-$`point2` |
```
/**
* Compute point substraction
* @param point1 First BabyJub point
* @param point2 Second BabyJub point
* @returns Substraction result point
*/
function ecSub(point1: Point, point2: Point): Point
```
#### `derivePrivateKey`
- *Description*: derives private key from a given seed
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`seed` | Uint8Array | private key seed |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Scalar | private key |
```
/**
* Derives private key
* @param seed key generation seed
* @returns private key
*/
function derivePrivateKey(seed: Uint8Array) : Scalar
```
#### `genPrivateKey`
- *Description*: Samples a private key as a random scalar for BabyJub curve
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Scalar | private key |
```
/**
* Samples a private key as a random scalar for BabyJub curve
* @returns Private key
*/
function genPrivateKey() : Scalar
```
#### `genPublicKey`
- *Description*: Deterministicly computes a public key on BabyJub curve corresponding to a private key
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`privateKey` | Scalar | private key |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Point | public key corresponding to `privateKey` |
```
/**
* Deterministicly computes a public key from a private key
* @param privateKey Exponent to Base8 on BabyJub curve
* @returns Public key
*/
function genPublicKey(privateKey: Scalar): Point
```
#### `genKeyPair`
- *Description*: Randomly generate a key-pair of `privateKey` and the corresponding `publicKey` on BabyJub curve
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | KeyPair | (private key, public key) |
```
/**
* Genereate a key-pair of `privateKey` and the corresponding `publicKey` on BabyJub curve
* @returns Key-pair
*/
function genKeyPair(): KeyPair
```
#### `bigint2Uint8Array`
- *Description*: Converts a bigint to Uint8Array of length 32
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`bi` | bigint | big integer to convert |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Uint8Array | Uint8Array of length 32 |
```
/**
* Converts big integer to Uint8Array of length 32
* @param bi big integer to convert
* @returns Uint8Array
*/
function bigint2Uint8Array(bi: bigint): Uint8Array
```
#### `uint8Array2Bigint`
- *Descriptipn*: Converts a Uint8Array to bigint
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`arr` | Uint8Array | Uint8Array to convert |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | bigint | bigint|
```
/**
* Converts Uint8Array to big integer
* @param arr Uint8Array to convert
* @returns big integer
*/
function uint8Array2Bigint(arr: Uint8Array): bigint
```
#### `bitArray2Bigint`
- *Description*: Converts a bit array to big integer
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`ba` | any | bit array to convert |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | bigint | bigint|`
```
/**
* Converts bit array to big integer
* @param ba bit array to convert
* @returns big integer
*/
function bitArray2Bigint(ba): bigint
```
#### `bitArray2uint8Array`
- *Description*: Converts a bit array to uint8Array of size 32
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`ba` | any | bit array to convert |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Uint8Array | Uint8Array of length 32|
```
/**
* Converts bit array to uint8Array of size 32
* @param ba bit array to convert
* @returns uint8Array
*/
function bitArray2uint8Array(ba): Uint8Array
```
#### `bigintArray2uint8Array`
- *Description*: Converts a bigint array to uint8Array
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`bia` | any | bit array to convert |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Uint8Array | Uint8Array of length (32 * bia.length)|
```
/**
* Converts bigint array to uint8Array
* @param bia bigint array to convert
* @returns uint8Array
*/
function bigintArray2uint8Array(bia: bigint[]): Uint8Array
```
#### `sha256Signals`
- *Description*: Computes sha256 hash of a bigint array and returns the result as bigint
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`arr` | bigint[] | inputs to the hash function |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | bigint | sha256 hash of the input|
```
/**
* Computes sha256 hash of a bigint array
* @param arr array of bigints
* @returns sha256 hash of the input as a bigint
*/
function sha256Signals(arr: bigint[]): bigint
```
#### `getSignOfY`
- *Description* : Returns the sign of the $y$-coordinate of a $\mathbb{G}_1$ point
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`point` | Point | $\mathbb{G}_1$ point |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | number | sign of $y$-coordinate of `point`|
```
/**
* Return the sign of coordinate y
* @param point uncompressed babyjub point
* @returns sign of y
*/
function getSignOfY(point: Point): number
```
#### `deriveMnemonicFromSignature`
- *Description*: Derives a mnemonic phrase using an Uint8Array as a seed
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`seed` | Uint8Array | Metamask signature |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | string | mnemonic phrase|
```
/**
* derives mnemonic using Metamask signature as seed
* @param seed user's signature
* @returns mnemonic for Elara account
* @dev signature should be verified before calling this function
*/
function deriveMnemonicFromSignature(seed: Uint8Array): string
```
#### `deriveMasterSeedFromSignature`
- *Description*: derives a master from a uint8Array
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`seed` | Uint8Array | Metamask signature |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Uint8Array | master seed to be used for private key generation|
```
/**
* derives master seed using Metamask signature as seed
* @param seed user's signature
* @returns masterseed for Elara account
* @dev signature should be verified before calling this function
*/
function deriveMasterSeedFromSignature(seed: Uint8Array): Uint8Array
```
#### `derivePrivateKeyFromSignature`
- *Description*: derives a babyJubjub private key from a Uint8Array
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`seed` | Uint8Array | Metamask signature |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Scalar | babyJubjub private key|
```
/**
* derives Elara private key using Metamask signature as seed
* @param seed user's signature
* @returns private key for Elara account
* @dev signature should be verified before calling this function
*/
function derivePrivateKeyFromSignature(seed: Uint8Array): Scalar`
```
#### `encryptDetails`
- *Description*: Encrypts the transaction details(sender, recipient, amount) and returns the ciphertext
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`sk` | Scalar | private key |
|`pk` | Point | public key |
|`details` | TransactionDetails | transaction details to encrypt|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | TransactionCiphertext | ciphertext|
```
function encryptDetails(
sk: Scalar,
pk: Point,
details: TransactionDetails,
): TransactionCiphertext
```
#### `decryptDetails`
- *Description*: decrypts a transaction ciphertext and returns transaction details
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`sk` | Scalar | private key |
|`pk` | Point | public key |
|`details` | TransactionCiphertext | transaction ciphertext to decrypt |
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | TransactionDetails | transaction details|
```
function decryptDetails(
sk: Scalar,
pk: Point,
ciphertext: TransactionCiphertext,
): TransactionDetails
````
### [Account](https://github.com/projecteuanthe/elara-crypto/blob/main/src/account.ts)
```
/**
* defines an Account by its public/private key pair
*/
export class Account {
private privateKey: Scalar;
private publicKey: Point;
constructor(privateKey?: Scalar) {
this.privateKey = privateKey ?? genPrivateKey();
this.publicKey = ecMulBase(this.privateKey);
}
```
#### `getPrivateKey`
- *Description*: returns private key of the account
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Scalar | private key|
```
/**
* @returns private key of the account
*/
getPrivateKey(): Scalar
```
#### `getPublicKey`
- *Description*: returns public key of the account
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Point | public key|
```
/**
* @returns public key of the account
*/
getPublicKey(): Point
```
#### `getBalance`
- *Description*: decrypts given ciphertext and return the result
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`ciphertext` | ElGamalCiphertext | ciphertext|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | Point | $g^{plaintext}$|
```
/**
* decrypts given ciphertext
* @param ciphertext el-gamal ciphertext
* @returns g^plaintext
*/
getBalance(ciphertext: ElGamalCiphertext): Point
```
#### `encrypt`
- *Description*: encrypts an amount for a public key
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`balance` | Scalar | plaintext|
|`publicKey` | Point | receiver's public key|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | ElGamalCiphertext | encryption of `balance` under `publicKey`|
```
/**
* encrypts an amount for a public key
* @param balance plaintext to encrypt
* @param publicKey
* @returns encryption of balance under publicKey
*/
static encrypt(balance: Scalar, publicKey: Point) :ElGamalCiphertext
```
#### `randomize`
- *Description*: randomizes a ciphertext
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`ciphertext` | ElGamalCiphertext | ciphertext to randomize|
|`publicKey` | Point | owner of the ciphertext|
|`r` |Scalar | randomness value to use during randomization|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `result` | ElGamalCiphertext | randomized ciphertext of the same plaintext|
```
/**
* randomizes a ciphertext
* @param ciphertext ciphertext to randomize
* @param publicKey owner of the ciphertext
* @param r randomness value to use during randomization
* @returns randomized ciphertext of the same plaintext
*/
static randomize(ciphertext: ElGamalCiphertext, publicKey: Point, r: Scalar): ElGamalCiphertext
```
#### `deposit`
- *Description*: computes the resultant ciphertext after depositing an amount
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`amount` | Scalar | deposit amount|
|`oldCiphertext` | ElGamalCiphertext | current balance ciphertext|
|`publicKey` | Point | owner of the ciphertext|
|`r` |Scalar | randomness value to use during randomization|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| | Scalar | random value that is used while encrypting the amount |
| | ElGamalCiphertext | alance ciphertext after adding the deposit amount to the old ciphertext|
```
/**
* computes the resultant ciphertext after depositing an amount
* @param amount to deposit
* @param oldCiphertext current balance ciphertext
* @returns random value that is used while encrypting the amount and
* balance ciphertext after adding the deposit amount to the old ciphertext
*/
deposit(amount: Scalar, oldCiphertext: ElGamalCiphertext)
: [Scalar, ElGamalCiphertext]
```
#### `SignPoseidon`
- *Description*: computes EdDSA signature with Poseidon used as hash function of a given message
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`message` | bigint | message to sign|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| | SchnorrSignature | signature |
```
/**
* computes EdDSA signature with Poseidon used as hash function of a given message
* @param message to sign
* @returns EdDSA signaure
*/
SignPoseidon(message: bigint): SchnorrSignature
````
#### `VerifyPoseidon`
- *Description*: checks if an EdDSA signature is valid
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`publicKey` | any | publicKey of the signer derived by `eddsa.prv2pub(prvKey)`|
|`message` | bigint | signed message|
|`sig` | SchnorrSignature | signature|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| | boolean | `true` if the signature is valid, `false` otherwise |
```
/**
* checks if an EdDSA signature is valid
* @param publicKey of the signer derived by eddsa.prv2pub(prvKey)
* @param message
* @param sig
* @returns true if given signature is valid, false otherwise
* @dev this publicKey is different than account.getPublicKey()
*/
static VerifyPoseidon(publicKey: any[], message: bigint, sig: SchnorrSignature): boolean
```
### [EdDSA-MuSig2](https://github.com/projecteuanthe/elara-crypto/blob/main/src/eddsa-musig2.ts)
This library implements Musig2 protocol for EdDSA as shown [in](https://eprint.iacr.org/2020/1261.pdf) with
the addition named Musig2* suggested in Section B of the paper. We implement the $\nu = 2$ (NUMBER_OF_NONCES) version, meaning there are 2 nonces generated by each party.
This implementation follows [this](https://github.com/ZenGo-X/multi-party-eddsa/blob/f5e825121c7fa2356482070adceda93c8db08ae8/src/protocols/musig2/mod.rs).
#### `keyAggregation`
- *Description*: aggregates public keys of the group and computes musig coeefficient of the caller
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`publicKeys` | Point[] | publicKeys that are derived from the expanded private key|
|`myPublicKey` | Point | caller's public key that is derived from the expanded private key|
|`sig` | SchnorrSignature | signature|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| | PublicKeyAgg | aggregated public key and the musig coefficient of the caller |
```
/**
* aggregates public keys and computes musig coefficient
* @param publicKeys of the parties
* @param myPublicKey public key of the user
* @returns aggregated public key and user's musig coefficient
*/
function keyAggregation(publicKeys: Point[], myPublicKey: Point) : PublicKeyAgg
```
#### `priv2ExpandedPriv`
- *Description*: computes expanded private key from user's private key
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`privateKey` | Scalar | private key|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| | Scalar | expanded private key |
```
/**
* computes expanded private key from user's private key
* @param privateKey
* @returns expanded private key
*/
function priv2ExpandedPriv(privateKey: Scalar): Scalar
```
#### `generatePartialNonces`
- *Description*: generate nonces for the caller which corresponds to sign part of the first round
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`keys` | KeyPair | private key, public key corresponding to expanded private key|
|`message`| bigint| message to sign|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| `privatePartialNonces` | bigint[] | private nonces of the caller |
| `publicPartialNonces` | Public[] | public nonces of the caller |
```
/**
* @param keys public/private key pair of the user
* @param message to sign
* @returns secret and public nonces of the user
*/
function generatePartialNonces(keys: KeyPair, message: bigint)
: {privatePartialNonces: bigint[], publicPartialNonces: Point[]}
```
#### `partialSign`
- *Description*: Combines SignAgg of the first round and Sign' of the second round. Combines the partial nonces of all parties and produces a partial signature of the caller.
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`noncesFromOtherParties` | Point[][] | public nonces of other parties|
|`myPrivatePartialNonces`| bigint[]| output of `generatePartialNonces`|
|`myPublicPartialNonces`|Point[]| output of `generatePartialNonces`|
|`aggPublicKey`|PublicKeyAgg| aggregated public key and musig coefficient|
|`myKeyPair`|KeyPair|private key and the public key that is computed from expanded private key|
|`message`|bigint|message to sign|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| | PartialSignature | partial signature of the caller |
```
/**
*
* @param noncesFromOtherParties public nonces of other parties
* @param myPrivatePartialNonces secret nonces of the user
* @param myPublicPartialNonces public nonces of the user
* @param aggPublicKey aggregated public key and musig coefficient of the user
* @param myKeyPair public/private key pair of the user
* @param message to sign
* @returns partial signature
*/
function partialSign(
noncesFromOtherParties: Point[][],
myPrivatePartialNonces: bigint[],
myPublicPartialNonces: Point[],
aggPublicKey: PublicKeyAgg,
myKeyPair: KeyPair,
message: bigint,
): PartialSignature
```
#### `aggregatePartialSignatures`
- *Description*: Combines SignAgg' and Sign''. Aggregates the partial signatures into the final signature.
| Input | Type | Description |
| :-------- | :-------- | :-------- |
|`myPartialSig` | PartialSignature | partial signature of the caller produced by `PartialSign`|
|`partialSigFromOthers`| PartialSignature[]| partial signatures of the other parties|
| Output | Type | Description |
| :-------- | :-------- | :-------- |
| | SchnorrSignature | final signature |
```
/**
* aggregates partial signatures into the final signature
* @param myPartialSig users partial signature
* @param partialSigsFromOthers partial signatures of others
* @returns final eddsa signature that can be verified with aggregated public key
*/
function aggregatePartialSignatures(
myPartialSig: PartialSignature,
partialSigsFromOthers: PartialSignature[],
)
: SchnorrSignature
```
###### tags: `SILENT` `references`
# Silent ZKPs
[toc]
## Baby JubJub Curve
**Specification**
Let $F_r$ be the prime finite field with $r$ elements, where
```
r = 21888242871839275222246405745257275088548364400416034343698204186575808495617
```
Let $E$ be the twisted Edwards elliptic curve defined over $F_r$ described by equation
```
ax^2 + y^2 = 1 + dx^2y^2
```
with parameters
```
a = 168700
d = 168696
```
We call Baby Jubjub the curve $E(F_r)$, that is, the subgroup of $F_r$-rational points of $E$.
**Order**
Baby Jubjub has order
```
n = 21888242871839275222246405745257275088614511777268538073601725287587578984328
````
which factors in
```
n = h x l
```
where
```
h = 8
l = 2736030358979909402780800718157159386076813972158567259200215660948447373041
```
The parameter $h$ is called cofactor and $l$ is a prime number of 251 bits.
**Generator Point**
The point $G = (x,y)$ with coordinates
```
x = 995203441582195749578291179787384436505546430278305826713579947235728471134
y = 5472060717959818805561601436314318772137091100104008585924551046643952123905
```
generates all $n$ points of the curve.
**Base Point**
The point $B = (x,y)$ with coordinates
```
x = 5299619240641551281634865583518297030282874472190772894086521144482721001553
y = 16950150798460657717958625567821834550301663161624707787222815936182638968203
```
generates the subgroup of points $P$ of Baby Jubjub satisfying $l * P = O$. That is, it generates the set of points of order $l$ and origin $O$.
All EC operations are carried out in the subgroup with the base point $B$.
## Templates
### `BalanceUpdate()`
Use the additively homomorphic property of ElGamal encryption to update the balance
- Input
- `inC2`: Point; second part of ElGamal Ciphertext $(C_1, C_2)$ of a balance
- `amount`: Scalar; amount to be added
- Output
- `outC2`: Point; second part of ElGamal Ciphertext $(C_1, C_2)$ of the updated balance
### `BalanceVerify()`
Decrypts the ciphertext and verifies whether the decrypted balance is equal to `amount`
- Input
- `amount`: Scalar; balance
- `privateKey`: Scalar; private key to decrypt the ciphertext
- `C1`: Point; first part of ElGamal Ciphertext $(C_1, C_2)$
- `C2`: Point; second part of ElGamal Ciphertext $(C_1, C_2)$
### `Decompress(N)`
Decompress a set of compressed points
- Parameters
- `N`: Scalar; number of points to be decompressed
- Input
- `y`: Scalar[]; y coordinates of compressed points
- `signs`: Scalar; packed signs for y coordinates
- Output
- `x`: Scalar[]; first part of ElGamal Ciphertext $(C_1, C_2)$
### `Encrypt(MESSAGE_SIZE)`
Encrypts a message using MiMC symmetric encryption
- Parameters
- `MESSAGE_SIZE`: Scalar; size of the message as a number of signals
- Input
- `key`: Scalar; symmetric key
- `iv`: Scalar; initialization vector
- `message`: Scalar[]; message to be encrypted
- Output
- `ciphertext`: Scalar[]; encryption of the message
### `Randomize()`
Randomize ElGamal ciphertext by adding new randomness to $C_1$ and $C_2$
- Input
- `inC1`: Point; first part of ElGamal Ciphertext $(C_1, C_2)$
- `inC2`: Point; second part of ElGamal Ciphertext $(C_1, C_2)$
- `r`: Scalar; randomness
- `y`: Point; public key used to encrypt the ciphertext
- Output
- `outC1`: Point; first part of randomized ElGamal Ciphertext $(C_1, C_2)$
- `outC1`: Point; second part of randomized ElGamal Ciphertext $(C_1, C_2)$
### `Selector()`
Selects a ciphertext and a publicKey from a ring of size eight at a specific index
- Input
- `inC1`: Point[8]; ring of first parts of ElGamal Ciphertext $(C_1, C_2)$
- `inC2`: Point[8]; ring of second parts of ElGamal Ciphertext $(C_1, C_2)$
- `inPK`: Point[8]; ring of public keys associated with the ciphertext
- `index`: Scalar; index of the to be selected ciphertext and public key
- Output
- `outC1`: Point; first part of the selected ElGamal Ciphertext $(C_1, C_2)$
- `outC2`: Point; second part of the selected ElGamal Ciphertext $(C_1, C_2)$
- `outPK`: Point; selected public key
### `Utils.MulBase`
Multiply a scalar with the base point $B$
- Input
- `e`: Scalar; value
- Output
- `out`: Point; group element $eB$
### `Utils.MulAny`
Multiply a scalar with a given point
- Input
- `e`: Scalar; value
- `in`: Point; group element
- Output
- `out`: Point; group element $e(in)$
### `Utils.ECDH`
Generates a shared symmetric key using Diffie Hellman protocol
- Input
- `privateKey`: Scalar; private key of the sender
- `publicKey`: Point; public key of the recipient
- Output
- `key`: Scalar; generated shared key
## Main Circuits
### Deposit
To deposit an amount into an Silent account, one updates the oldCiphertext to reflect the amount after the deposit
- Public input
- amount: Scalar
- signs: Scalar; signs of $y$-coordinates signals
- yPublicKey: Scalar; $y$-coordinate of the public key
- yInC2: Scalar; $y$-coordinate of input second part of the ciphertext
- yOutC2: Scalar; $y$-coordinate of output second part of the ciphertext
##### Pseudocode
1. Decompress `publicKey`, `inC2`, `outC2`.
2. updateBalance (add `amount`*G to `inC2`).
3. check if the result is equal to `outC2`.
- [ ] ==this should be coherent with [Deposit definition](https://hackmd.io/lgfE806nTKegNAQkmiDpKA#Deposit) given in [Silent Protocol Yellowpaper](https://hackmd.io/lgfE806nTKegNAQkmiDpKA).==
### Transfer
To transfer an amount to a recipient, the sender forms an anonymity set of size 8, deducts the amount from sender's balance and adds it to recipient's balance, randomizes all of the ciphertexts, and encrypts transaction details for the recipient and compliance.
- Public input
- `yInC1`: Scalar[8]; $y$-coordinates of the first parts of the ciphertexts before the transfer`(inC1, inC2)`
- `yInC2`: Scalar[8]; $y$-coordinates of the second parts of the ciphertexts before the transfer`(inC1, inC2)`
- `yOutC1`: Scalar[8]; $y$-coordinates of the first parts of the ciphertexts after the transfer`(inC1, inC2)`
- `yOutC2`: Scalar[8]; $y$-coordinates of the second parts of the ciphertexts after the transfer`(inC1, inC2)`
- `yPublicKeys`: Scalar[8]; $y$-coordinates of the public keys
- `yEphemeralSenderPk`: Scalar; $y$-coordinate of the ephemeral key for the sender
- `yEphemeralRecipientPk`: Scalar; $y$-coordinate of the ephemeral key for the recipient
- `yAMLPK`: Scalar; $y$-coordinate of the ephemeral key for the compliance account
- `signs`: Scalar; signs of $y$-coordinates
- `iv`: Scalar[2]; initial vectors of transactionCiphertext and amlCiphertext
- `transactionCiphertext`: Scalar[5]; encryption of the transaction details for the recipient
- `amlCiphertext`: Scalar[5]; encryption of the transaction details for the compliance
- Private input
- `senderPrivateKey`: Scalar; sender's private key
- `senderIndex`: Scalar; sender's index in the ring
- `recipientIndex`: Scalar; recipient's index in the ring
- `valueIn`: Scalar; sender's balance
- `valueOut`: Scalar; transferred amount
- `random`: Scalar; random value to randomize the ciphertexts
- `ephemeralR`: Scalar; random value to get ephemeralSenderPk and ephemeralRecipientPK
- *Pseudocode*
1. Uncompress points
1. Select the sender's and recipient's (publicKey, ciphertext) tuple from the given ring
1. Verify knowledge of `senderPrivateKey`
1. Verify sender's ciphertext decrypts to `valueIn`
1. Verify `valueIn` $\geq$ `valueOut`
1. Subtract `valueOut` from the sender's balance
1. Add `valueOut` to the recipient's balance
1. Randomize each ciphertext `(inC1[i],inC2[i])` using `random` and check if the result match `(outC1[i], outC2[i])`
1. Verify that ephemeral public keys are formed correctly
1. Derive shared keys; one for the sender-recipient and one for sender-compliance
1. Encrypt transaction details for recipient and compliance and check if given ciphertexts matches the results
### Withdraw
- To transfer an amount to a recipient, the sender forms an anonymity set of size 8, deducts the amount from sender's balance and adds it to recipient's balance, randomizes all of the ciphertexts, and encrypts transaction details for the recipient and compliance.
- Public input
- `yInC1`: Scalar[8]; $y$-coordinates of the first parts of the ciphertexts before the transfer`(inC1, inC2)`
- `yInC2`: Scalar[8]; $y$-coordinates of the second parts of the ciphertexts before the transfer`(inC1, inC2)`
- `yOutC1`: Scalar[8]; $y$-coordinates of the first parts of the ciphertexts after the transfer`(inC1, inC2)`
- `yOutC2`: Scalar[8]; $y$-coordinates of the second parts of the ciphertexts after the transfer`(inC1, inC2)`
- `yPublicKeys`: Scalar[8]; $y$-coordinates of the public keys
- `yAMLPK`: Scalar; $y$-coordinate of the ephemeral key for the compliance account
- `signs`: Scalar; signs of $y$-coordinates
- `valueOut`: Scalar; withdrawal amount
- `extra`: Scalar; address of recipient or hash of Defi interact parameters
- `yIndexCiphertext`: Scalar[3]; `y`-coordinates of `C1`, `C2_S`, and `C2_AML` which form ElGamal ciphertext `(C1, C2_S)` and `(C1, C2_AML)` that encrypt the sender's index in the ring by the sender's and AML's public keys, respectively
- Private input
- `senderPrivateKey`: Scalar; sender's private key
- `index`: Scalar; sender's index in the ring
- `valueIn`: Scalar; sender's balance
- `random`: Scalar; random value to randomize the ciphertexts
- `r`: Scalar; random for computing `C1` of `yIndexCiphertext`
- *Pseudocode*
1. Uncompress points
1. Select the sender's (publicKey, ciphertext) tuple from the given ring
1. Verify knowledge of `senderPrivateKey`
1. Verify sender's ciphertext decrypts to `valueIn`
1. Verify `valueIn` $\geq$ `valueOut`
1. Subtract `valueOut` from the sender's balance
1. Add `valueOut` to the recipient's balance
1. Randomize each ciphertext `(inC1[i],inC2[i])` using `random` and check if the result match `(outC1[i], outC2[i])`
1. Encrypt the sender index using ElGamal encryption using the sender PK and AML PK
### DepositFromDefi
- To move funds from a DeFi into a Silent account, a user forms an anonymity set and get their balance ciphertexts. Then adds the desired amount to the recipients balance and randomizes all of the balance ciphertexts. Finally, encrypts the transaction details, in this case recipient index.
- Public input
- `yInC1`: Scalar[8]; $y$-coordinates of the first parts of the ciphertexts before the transfer`(inC1, inC2)`
- `yInC2`: Scalar[8]; $y$-coordinates of the second parts of the ciphertexts before the transfer`(inC1, inC2)`
- `yOutC1`: Scalar[8]; $y$-coordinates of the first parts of the ciphertexts after the transfer`(inC1, inC2)`
- `yOutC2`: Scalar[8]; $y$-coordinates of the second parts of the ciphertexts after the transfer`(inC1, inC2)`
- `yPublicKeys`: Scalar[8]; $y$-coordinates of the public keys
- `yAMLPK`: Scalar; $y$-coordinate of the ephemeral key for the compliance account
- `signs`: Scalar; signs of $y$-coordinates
- `valueIn`: Scalar; deposited amount
- `extra`: Scalar; address of recipient or hash of Defi interact parameters
- `yIndexCiphertext`: Scalar[3]; `y`-coordinates of `C1`, `C2_S`, and `C2_AML` which form ElGamal ciphertext `(C1, C2_S)` and `(C1, C2_AML)` that encrypt the sender's index in the ring by the sender's and AML's public keys, respectively
- Private input
- `index`: Scalar; sender's index in the ring
- `random`: Scalar; random value to randomize the ciphertexts
- `r`: Scalar; random for computing `C1` of `yIndexCiphertext`
- *Pseudocode*
1. Uncompress points
1. Select the recipient's (publicKey, ciphertext) tuple from the given ring
1. Add valueIn to recipient's ciphertext
1. Randomize each ciphertext `(inC1[i],inC2[i])` using `random` and check if the result match `(outC1[i], outC2[i])`
1. Encrypt the recipient index using ElGamal encryption using the sender PK and AML PK
### SecretSharing
- *Description*: Implements the secret sharing for threshold decryption. SHARES represents the number of total shares and (t for short) represents the number of shares that are required to decrypt a message.
For a polynomial $p(x) = p_0 + p_1 x + p_2 x^2 + ... + p_{t-1} x^{t-1}$, computes $p_i G$ and the shares by evaluating the polynomial at $\{1, \ldots, t\}$. Finally, verifies the signatures on the shares.
| Input | Type | Description |
| :-------- | :-------- | :-------- |
| **Public Inputs** |
| `ySignPubKey` | Field | $y$-coordinates of the signature public key|
| `ySignatureRs` | Field[SHARES] | $y$-coordinates of the signatures first part`(R, s)` |
| `signaturesS` | Field[SHARES] | second parts of the signatures`(R, s)` |
| `yBroadcast` | Field[THRESHOLD] |$y$-coordinates of the broadcasted points $p_i G$|
| `signs` | Field |signs of the $y$-coordinates of the above points |
| **Private Inputs** | |
| `polynomial` | Field[THRESHOLD][k] | coefficients of the polynomial |
| `privateKey` | Field | private key of the member |
| `secretShares` | Field[SHARES][k] | shares of the members for the private key|
- *Pseudocode*
0. Uncompress points
1. Construct polynomial coefficients and secret shares (they are provided in chunks and need to be converted to a field element)
2. Compute $p_i G$ and show that they are equal to 'yBroadcast[i]'
3. Show that $p_0$ is equal to `privateKey`
4. Show that secret shares are computed correctly
5. Verify the signatures on the secret shares
## ZKP Desicion Rationale
### Groth16 vs. PlonK
- Our Benchmarks
- [ ] ==Oznur's benchmark results will be here!==
SHA256 with 8 256-bit inputs
| | |8 Hashes | 16 Hashes | |
| -------- | -------- | -------- | -------- | -------- |
| | PLONK | GROTH16 | PLONK | GROTH16 |
| zkey size | 1,64 GB | 112 MB |3,27 GB | 208 MB|
| Verification key size | 2044 B | 2927 B | 2043 B| 2923 B|
| Proof size | 2342 B | 805 B | 2339 B| 806 B |
| Prover Time | 281377 ms | 4775 ms |573334 ms| 8422 ms |
| SC Deployment Gas Cost | 1719157 | 1090473 | 1725836| 1090473|
| Verification Cost | 293358 | 230479 | 295532| 230479|
- Aztec's Benchmarks
1. 2019-12-18: [PlonK Benchmarks I — 2.5x faster than Groth16 on MiMC](https://medium.com/aztec-protocol/plonk-benchmarks-2-5x-faster-than-groth16-on-mimc-9e1009f96dfe)
<img style="display:block;margin:48px auto;padding:1px;border:1px #eee;width:50%;" src="https://miro.medium.com/max/1400/1*zQMdF6fxikleW4E0HcsYXw.png" />
2. 2020-02-20: [PlonK Benchmarks II — ~5x faster than Groth16 on Pedersen Hashes](https://medium.com/aztec-protocol/plonk-benchmarks-ii-5x-faster-than-groth16-on-pedersen-hashes-ea5285353db0)
<img style="display:block;margin:48px auto;padding:1px;border:1px #eee;width:50%;" src="https://miro.medium.com/max/1400/1*KbIX2jYLpYOSIUuCwUSZQA.png" />
- Dusk Benchmark
1. 2020-04-20: [Bulletproof vs. PlonK](https://dusk.network/news/zero-knowledge-plonk-demo#:~:text=scale%20drastically%20better.-,Benchmark,-times%20/%20faster%20than)
<img style="display:block;margin:48px auto;padding:1px;border:1px #eee;width:75%;" src="https://lh5.googleusercontent.com/cjGfqTEPbgztK9fzdInuvsPofX_P8bgTe_Ik-WTw3l5mBmhinyeOtVaPykFieVp8e7i9tSIsM4IUGUyX2vT5VOe8jrqtQOpvx7pFYOYAv7QYBZahrlCrDgdnyk5zmJjH4iRN_z7D" />
- Jerry Ho on Smart Contract Research Forum
1. 2021-04-01: [Research Summary: PlonK: Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of Knowledge](https://www.smartcontractresearch.org/t/research-summary-plonk-permutations-over-lagrange-bases-for-oecumenical-noninteractive-arguments-of-knowledge/382) This includes PlonK's paper benchmarks
<img style="display:block;margin:48px auto;padding:1px;border:1px #eee;width:75%;" src="https://aws1.discourse-cdn.com/business5/uploads/smartcontractresearch/original/1X/6a90978db2d34be7576c93f0256a966c3e33a39e.png" />
<img style="display:block;margin:48px auto;padding:1px;border:1px #eee;width:75%;" src="https://aws1.discourse-cdn.com/business5/uploads/smartcontractresearch/original/1X/e2f1c293728ad028d13720eb02108cbca6c38427.png" />
<img style="display:block;margin:48px auto;padding:1px;border:1px #eee;width:75%;" src="https://aws1.discourse-cdn.com/business5/uploads/smartcontractresearch/original/1X/d13573d871f62d20c6e57eb37ac94504b01d1b67.png" />
###### tags: `SILENT`
# Silent Protocol Trusted Setup Ceremony
[toc]
## Background
### What is trusted setup ceremony?
<!--- ### Intro
- we use [Groth16](https://eprint.iacr.org/2016/260) which is the first fully succinct NIZK proof protocol based on CRS. Basic reasons for choosing Groth16 is its the shortest proof and fastest timings features.
- but we need to solve its Common Reference String has to be pre-processed as structured reference string (SRS) within a trusted setup ceremony.
- In fact, Ceremony is used to generate the proving and corresponding verification keys that is specific to a circuit (a drawback of Groth16).
- we are going to need to have different proving/verifying key for each circuit template
- among different implementations we are going to use [BGM17](http://eprint.iacr.org/2017/1050) - which was also used in Zcash Sapling, Aztec protocol, Filecoin, Semaphore, Loopring, Tornado Cash, Plumo Ceremony, and Hermez etc.
- BGM17 has two phases, phase-1 and pahse-2.
- by utilizing already handled phase-1 phase (perpetual powers of tau) computations, we are going to run only phase-2 for each cicuit. --->
zk-SNARKs require the generation of certain parameters in order to achieve high efficiency (small proof sizes, fast proving and verifying time). These parameters are generated by another set of parameters which MUST remain secret. We call these secret parameters the "toxic waste". If a prover knows these secrets, then they can generate valid proofs for invalid statements, breaking soundness. This is undesired!
In order to guarantee that no prover will ever know these secrets, we can generate them in a distributed manner. Each participant in this so-called "ceremony" will contribute to the generation of the parameters with their own secret. If at least 1 participant is honest and destroys their secret, then there should be no way for a malicious prover to create fake proofs.
Trusted setup ceremonies made-up of two phases:
- Phase-1 universal up to the number of constraints
- Phase-2 specific to each circuit

MMORPC:

### Why do we need it?
Silent utilizes three different Groth16-based zk-SNARK circuits, namely
- *[Deposit](https://hackmd.io/7gDJp7jWQiiwe_eSWk5mWw#Deposit-Template)*,
- *[Transfer](https://hackmd.io/7gDJp7jWQiiwe_eSWk5mWw#Transfer),*
- *[Withdraw](https://hackmd.io/7gDJp7jWQiiwe_eSWk5mWw#Withdraw)*
for assuring shielded transactions. For each circuit we need to perform different phase-2 of trusted setup ceremony.
This ceremony lets us to build branding and trust to assure honesty of the project as well.
## Groth-16 based Trusted Setup Ceremony
### Overview

#### Ceremony Workflow
1. first we'll finalize Groth16-based Circom 2.0 circuits and contracts development - ongoing
2. get the smart contract and the circuts audited - external
3. in the meantime, we need to prepare ceremony setup
- utilize previous phase-2 repos
- develop user friendly docker images, related scripts for different OS'es,
- source code for advanced users, and related instructions
- back-end and front-end design/development,
4. run test simulations only for phase-2, by utilizing perpetual powers of tau data as an input, for simple circuits and then the actual circuits.
5. initialize and run the web page for the ceremony
- initial: before the ceremony
- well documented ceremony details
- links to Github relates repos
- participation instructions
- verification instructions
- Google form registration
- going live and then updates: during the ceremony
- Contribution balancing and time slot arrangement
- current list of attestations
- final update:
- publish final list of attestations
- generate final outputs, proving & verifying keys
- github updates to keep for later verifications
- keep the web page on hold and updated with closing anouncements
6. Accompany the ceremony with community posts and announcements
#### Tasks
(completion date expected: April 10th (at most 15th), 2022)
##### DevOps
1. Creating Github repos
- fork the Celo Plumo phase-2 repo and utilize KobiGur's phase-2 repo for specific curve, namely bn128
- update according to our constraints and ciruits
- prepare repo for contribution with source code
2. Dockerizing
- multiple OS support
3. Scripts
- contributer commands
- Contributer Instructions
##### Back-end Development
1. Hosting - host for the client app
2. Storage - circuit files, contribution files
3. Functions - periodically invoked operations
- contribution management, balancing
- coordinator verification
4. message queue - for balancing the contributions across the ciruits
6. social media attestation inclusion
##### Front-end Development
Example: [Celo Plumo Ceremony Page](https://celo.org/plumo)
1. Google Form
2. Instructions pages
3. Client scripts
4. Contribution status
5. Attestion sharing
##### Testing
1. Initial testing with basic circuits
2. Actual testing with our circuits
##### Live
1. Contribution balancing and time slot arrangement
2. current list of attestations
3. final update:
- publish final list of attestations
- generate final outputs, proving & verifying keys
- github updates to keep for later verifications
- keep the web page on hold and updated with closing anouncements
### Related Ceremony Repos
1. Celo Plumo Ceremony setup - https://github.com/orgs/celo-org/repositories?q=snark-setup&type=all&language=&sort=
2. Kobi Gurkan's phase2-bn254 repo - https://github.com/kobigurk/phase2-bn254
2. public good which will be utilized instead of phase-1 - https://github.com/weijiekoh/perpetualpowersoftau
3. Trusted setup MPC UI - https://github.com/glamperd/setup-mpc-ui
4. Aleo trusted setup - https://github.com/AleoHQ/aleo-setup and https://github.com/AleoHQ/aleo-setup-integration-test
<!----
### Issues to be addressed
1. Pre-ceremony teasers
- techie posts
- tweets etc.
2. Ceremony will be handled within community forming process,
- Well known figures, Vitalik, Kobi Gurkan etc., will be invited, announced, and participate in the ceremony (with the help of investers)
- Two strategy
- increase the number of participant as much as possible and keep the ceremony period open for a few weeks frame.
- instead of increasing of the participants, focus on complete the ceremony as fast as possible.
3. Ceremony must be accompanied with various techie and non-techie posts and news, how should we prepare for this.
- announcement of the ceremony
- tech post on Groth16 vs other to justify our choice
- tech post on Trusted setup ceremony, detailed participation instructions
- during the ceremony non techie news especially involvement of well known figures
- tech post on Trusted setup ceremony, detailed final verification instructions
4. We may place some awards for special participation (social medi tweets, vlogs, stories etc.) of end users, as it was in Celo Plumo ceremony.
5. How should we schedule this ceremony within our branding and marketing plan? --->
### Phase1
The following steps will be carried out once by the team.
1. Contribute to perpetual powers of tau (PPoT) project (individually for once)
PPoT aims to securely generate zk-SNARK parameters for circuits of up to $2^{28}$ (260+ million) constraints. This means that the process will generate twice as many minus one (530+ million) powers of tau.
Current state is held at [weijiekoh's PPoT repo](https://github.com/weijiekoh/perpetualpowersoftau) and it's at 71st attestation, ([Edward Fricker](https://github.com/weijiekoh/perpetualpowersoftau/tree/master/0071_edward_response)) with the
- [response](https://ppot.blob.core.windows.net/public/response_0071_edward) (49GB)
- [challenge](https://ppot.blob.core.windows.net/public/challenge_0072) (97GB) for next attestation.
We are going to contribute PPoT by getting in touch with Wei Jie via Twitter DM (@weijie_eth) or Telegram (@weijiek).
Steps required:
1. Utilize either [snarkjs](https://github.com/weijiekoh/perpetualpowersoftau/blob/master/snarkjs_instructions.md) or [phase2_bn254](https://github.com/weijiekoh/perpetualpowersoftau#instructions-for-each-participant). phase2_bn254 is better choice here, since it would take much longer with snarkjs (24hours, 2-3 days, respectively). Below, we follow [phase2_bn254](https://github.com/weijiekoh/perpetualpowersoftau#instructions-for-each-participant) instructions:
2. Set up a Linux machine and install Rust and Cargo
3. Download and compile the required source code:
```bash
git clone https://github.com/kobigurk/phase2-bn254.git --branch ppot_ceremony && \
cd phase2-bn254/powersoftau && \
cargo build --release
```
4. Download the latest [challenge](https://ppot.blob.core.windows.net/public/challenge_0072) (97GB) and rename it to `challenge`:
```bash
mv challenge_nnnn challenge
```
5. Check with the coordinator (or [weijiekoh's PPoT repo](https://github.com/weijiekoh/perpetualpowersoftau)) for the expected Blake2b hash of `challenge`.
6. Run the computation with `challenge` in your working directory:
```
cargo run --release --bin compute_constrained # generate response file
```
7. Enter the random seed at this prompt:
```
Will contribute to accumulator for 2^28 powers of tau
In total will generate up to 536870912 powers
Type some random text and press [ENTER] to provide additional entropy...
```
8. The compuation will run for about 24 hours on a fast machine (e.g an Azure compute VM - Standard F4s with 4 vcpus and 8GB memory).
9. When it is done, something like the following will be prompted:
```
Finishing writing your contribution to `./response`...
Done!
Your contribution has been written to `./response`
The BLAKE2b hash of `./response` is:
12345678 90123456 78901234 56789012
12345678 90123456 78901234 56789012
0b5337cd bb05970d 4045a88e 55fe5b1d
507f5f0e 5c87d756 85b487ed 89a6fb50
Thank you for your participation, much appreciated! :)
```
10. Upload the response file to the coordinator's server using SFTP or rsync.
11. Finally, document the process [like in this example]( https://github.com/weijiekoh/perpetualpowersoftau/blob/master/0027_alex_response/alex_attestation.md). Include the git commit hash of the `phase2-bn254` repository, from which the binaries are built, in the attestation. Sign the attestation with the Keybase account and post it to the mailing list.
### Phase2 Prep
#### Deposit
1. Prepare phase 2 with $2^{18}$ constraints since our Deposit circuit has constraints between $2^{17}$ and $2^{18}$.
>For time being, let's use [powersOfTau28_hez_final_18](https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_18.ptau)
> skip the step below for the time being.
```
snarkjs powersoftau prepare phase2 ppot72_beacon.ptau ppot72_18_final.ptau -v
```
2. Verify the final ptau
```
// snarkjs powersoftau verify ppot72_18_final.ptau
snarkjs powersoftau verify powersOfTau28_hez_final_18.ptau
```
3. Compile the deposit circuit
```
circom deposit.circom --r1cs --wasm --sym
```
Optionally, the information about the deposit circuit can be viewed by
```
snarkjs r1cs info deposit.r1cs
```
and it can be double checked
```
snarkjs r1cs print deposit.r1cs deposit.sym
```
4. Export r1cs to json
```
snarkjs r1cs export json deposit.r1cs deposit.r1cs.json
```
5. Calculate the witness
First, we create a file named `deposit_input.json` with the inputs for our deposit circuit:
```
cat <<EOT > deposit_input.json
{"privateKey": "4028640584965482970038354194174919909961218941572617324469619274553048906516",
"random": "6536182426233418169878146847054021857814320098209995520769436044577321354402",
"amount": "3",
"adapterHash": "1124345623345678",
"bjjPublicKey": "2174455474874728199061138974051935968624087969656836616417123334472988189351",
"bjjOldC1": "11583865286317341838935741916749233161396581848659689986339398564553576353131",
"bjjOldC2": "5325352831100603194493731750217751083060298192571643436510752756040601261580",
"bjjNewC1": "7171517431821016431015271993580853381811529726095707293265332921773135860014",
"bjjNewC2": "4967354418473975093021445161999013081549339056886353028875801460724947531043",
"signs": "26",
"inputsHash": "4918617833923935898287684881339365464038823774263859583703056488749952328945"
}
EOT
```
> "" notations may needed to be removed from the values because of eslint.
Now, we use the Javascript/WASM program created by circom in the directory deposit_js to create the witness (values of all the wires) for our inputs:
```
cd deposit_js
node generate_witness.js deposit.wasm ../deposit_input.json ../deposit_witness.wtns
```
> eslint-based errors may arise that can be handled with quickfix.
6. Groth16 Setup
```
snarkjs groth16 setup deposit.r1cs ppot72_18_final.ptau deposit_0000.zkey
```
7. Silent's initial contribuion to the phase 2 ceremony
```
snarkjs zkey contribute deposit_0000.zkey deposit_0001.zkey --name="SilentDAO" -v
```
with appropriate random input.
8. Prepare challenge for community contribution
```
snarkjs zkey export bellman deposit_0001.zkey deposit_challenge_phase2_0002
```
This `deposit_challenge_phase2_0002`will be the initial challenge for the first contributor during the ceremony.
#### Transfer
The similar steps given in Deposit section will be applied for `Transfer.circom` and finally the following challenge file will be created:
```
snarkjs zkey export bellman transfer_0001.zkey transfer_challenge_phase2_0002
```
#### Withdraw
The similar steps given in Deposit section will be applied for `Withdraw.circom` and finally the following challenge file will be created:
```
snarkjs zkey export bellman withdraw_0001.zkey withdraw_challenge_phase2_0002
```
### Phase2 Contribution
Upto this step, we have completed Phase1 contribution and Phase2 setup on our side and we are ready to receive contributions, with the corresponding challenge files for each circuit.
The ceremony coordinator needs to maintain contribution candidates' queues, preferably one queue for each circuit.
>we may need to simulate and test this, to have minimize waiting queue.
>meet-up over this: we expect not to have problem on this, but we'll keep an eye on it.
For each circuit,
1. the coordinator sends the `xxx_challenge_phase2_nnn(n+1)` (that starts from 0002) to next contributor in line and waits for her reponse that will be computed by
- basic contributor as
```
snarkjs zkey bellman contribute bn128 xxx_challenge_phase2_nnn(n+1) xxx_response_phase2_nnn(n+1) -e="some random text"
```
which will run in the front-end and get the random input `"some random text"` from the contributor
- advanced contributor with the docker images provided by us that would utilize the above command or Kobi Gurkan's phase2_bn254 repo.
2. Upon receiving the response, the coordinator imports it by
```
snarkjs zkey import bellman xxx_nnnn.zkey xxx_response_phase2_nnn(n+1) xxx_nnn(n+1).zkey -n="(n+1)th contribution name"
```
and verifies it by
```
snarkjs zkey verify xxx.r1cs ppot72_xx_final.ptau xxx_nnn(n+1).zkey
```
> this verification should be for latest two contributions, above command verifies all from the beginning, which would be unnecessarily costly.
3. If the contribution is verified succesfully, the coordinator generates next challenge by
```
snarkjs zkey export bellman xxx_nnn(n+1).zkey xxx_challenge_phase2_nnn(n+2)
```
and sends
`xxx_challenge_phase2_nnn(n+2)`
otherwise, sends
`xxx_challenge_phase2_nnn(n+1)`
to the next contributor and informs the previous contributor about the failure.
>here we should re-consider how to proceed! should we let current contributor to try again or move on to the next one, or should we decide based on the queue.
### Phase2 Finalization
Upon closing the ceremony window, the ceremony coordinator (or this can be pursued offline as well)
1. first verifies the latest zkey after the contributions
```
snarkjs zkey verify xxx.r1cs ppot72_xx_final.ptau xxx_nnn(n+k).zkey
```
2. applies a random beacon
```
snarkjs zkey beacon xxx_nnn(n+k).zkey xxx_final.zkey "Drand.love predetermined output" 10 -n="Final Beacon phase2"
```
3. Verify the final zkey
```
snarkjs zkey verify xxx.r1cs ppot72_xx_final.ptau xxx_final.zkey
```
4. Export the verification key
```
snarkjs zkey export verificationkey xxx_final.zkey xxx_verification_key.json
```
5. Create the proof
```
snarkjs groth16 prove xxx_final.zkey xxx_witness.wtns xxx_proof.json xxx_public.json
```
or create the proof and calculate the witness in the same command by running
```
snarkjs groth16 fullprove xxx_input.json xxx_js/xxx.wasm xxx_final.zkey xxx_proof.json xxx_public.json
```
6. Verify the proof
```
snarkjs groth16 verify xxx_verification_key.json xxx_public.json xxx_proof.json
```
7. Turn the verifier into a smart contract
```
snarkjs zkey export solidityverifier xxx_final.zkey xxx_verifier.sol
```
`xxx_verifier.sol` will be utilized as starting point for our own smart contract.
8. Simulate a verification call
```
snarkjs zkey export soliditycalldata xxx_public.json xxx_proof.json
```
## Previous Ceremonies
### BGM17
- https://github.com/ebfull/powersoftau
- https://github.com/ebfull/phase2
- https://gist.github.com/ebfull/bf62068eda56ce2e8731666fa21d1414
sean bowe's note on large mpc's
- https://github.com/zcash/zcash/issues/2247#issue-220489844
- Kobi Gurkan's phase-2 repo: https://github.com/kobigurk/phase2-bn254
- Perpetual powers of Tau repo: https://github.com/weijiekoh/perpetualpowersoftau
### Zcash ceremonies
- https://z.cash/technology/paramgen/
- https://electriccoin.co/blog/sapling-mpc/
- https://github.com/zcash-hackworks/sapling-mpc/wiki
- https://medium.com/@blockchainbilly/participating-in-the-zcash-sapling-mpc-8fdbe89d8838
- https://electriccoin.co/blog/completion-of-the-sapling-mpc/
- https://github.com/zcash-hackworks/sapling-mpc/
### Tornado Cash
#### Community posts:
- announcement: https://tornado-cash.medium.com/tornado-cash-trusted-setup-ceremony-b846e1e00be1
- completion: https://tornado-cash.medium.com/the-biggest-trusted-setup-ceremony-in-the-world-3c6ab9c8fffa#43d9
#### Github repo:
- https://github.com/tornadocash/trusted-setup-server
- https://github.com/tornadocash/phase2-bn254
- results repo: https://github.com/tornadocash/tornado-core/releases/tag/v2.1
#### Web page:
- current:
https://ceremony.tornado.cash/
- home:

- Contribute:

- Anonymous contribution:

- Instructions:

- Completion:

### Celo
#### Community posts:
- https://medium.com/celoorg/the-plumo-ceremony-ac7649e9c8d8
- https://www.youtube.com/watch?v=0HTkND1Lf2A
- https://www.youtube.com/watch?v=LKbDNc-LrA4
#### Github repo:
- https://github.com/celo-org/snark-setup, which is infadt forked from kobi Gurkan's phase2-bn254 repo:
https://github.com/kobigurk/phase2-bn254
- https://github.com/celo-org/snark-setup-coordinator
- https://github.com/celo-org/snark-setup-operator
- https://github.com/celo-org/plumo-ceremony-attestations
#### Web page:
- current:
https://celo.org/plumo
- home initial:
https://web.archive.org/web/20201210005256/https://celo.org/plumo
- to join the ceremony, Google form registration required:
https://web.archive.org/web/20210122191310/https://docs.google.com/forms/d/e/1FAIpQLScZswraVVC91RwToo_9qm-1QzGrxp7yjVeM2wzdTbL5T_lAgQ/viewform
awards:
- For the Plumo Ceremony, we’re excited to award the following prizes (terms and conditions apply):
- Fastest Contribution (Desktop) 1000 CELO
- Fastest Contribution (Cloud) 1000 CELO
- Most Creative Source of Entropy 1000 CELO
- Most Secure Machine Setup 1000 CELO
- contributions:
https://web.archive.org/web/20210817091342/https://celo.org/plumo

### Aztec
#### Github repo:
- https://github.com/AztecProtocol/Setup
#### web page:
-current:
https://ignition.aztecprotocol.com/
https://ignition.aztecprotocol.com/terminal
### Sephamore
- project repo: https://github.com/appliedzkp/semaphore
- community post: https://weijiek.medium.com/restarting-the-semaphore-random-value-generation-process-980e19db11da
- instructions: https://hackmd.io/oja21FipQ5KhQcXeyuQWFQ
- insturction for anonymous participation: https://hackmd.io/QKzT41VJTJai_FpF8B003w
- github: https://github.com/appliedzkp/semaphore-phase2-setup/blob/master/README.md
### Hermez ceremonies
- https://github.com/hermeznetwork/phase2ceremony_3
- https://github.com/hermeznetwork/phase2ceremony_4
- https://blog.hermez.io/hermez-trusted-setup-phase-2/
- https://web.archive.org/web/20210119205253/https://blog.hermez.io/zero-knowledge-proofing-hermez-a-quick-guide-to-our-cryptographic-setup/
- https://web.archive.org/web/20210119211539/https://blog.hermez.io/hermez-trusted-setup-phase-2/
- https://web.archive.org/web/20210119210313/https://blog.hermez.io/zero-knowledge-proofing-hermez-preparephase2-update/
### Zkopru
- https://medium.com/privacy-scaling-explorations/zkopru-trusted-setup-ceremony-f2824bfebb0f
- https://medium.com/privacy-scaling-explorations/trusted-setup-ui-update-f8f95fc17a37
## Extra Readings
1. [Zero-Knowledge Proofs](https://zkp.science/)
2. D. Benarroch, 2020, [Diving into the zk-SNARKs Setup Phase](https://medium.com/qed-it/diving-into-the-snarks-setup-phase-b7660242a0d7)
3. https://z.cash/technology/paramgen/
4. sean bowe's phase1 repo: https://github.com/ebfull/powersoftau
5. sean bowe's phase2 repo: https://github.com/ebfull/phase2
6. Sam Parker's medium post https://zeroknowledge.fm/the-power-of-tau-or-how-i-learned-to-stop-worrying-and-love-the-setup/
7. perpetual powers of tau: https://medium.com/coinmonks/announcing-the-perpetual-powers-of-tau-ceremony-to-benefit-all-zk-snark-projects-c3da86af8377
8. iden3 snarkjs: https://github.com/iden3/snarkjs
9. zkp ceremony instruction: https://hackmd.io/AFqIQYGCQDmNCXNVmA54-Q?both
10. NCC audit on Kobi Gurkan's phase2-bn254 repo: https://research.nccgroup.com/2020/06/24/security-considerations-of-zk-snark-parameter-multi-party-computation/
## Extra Resources
### Literature
- nice to read: [ZKproof's setup ceremony post](https://zkproof.org/2021/06/30/setup-ceremonies/).
- [BGM17](http://eprint.iacr.org/2017/1050) - used in Zcash Sapling, Aztec protocol, Filecoin, Semaphore, Loopring, Tornado Cash, Plumo Ceremony, and Hermez. Implementations:
- [Drake's optimistis pipelining](https://ethresear.ch/t/accelerating-powers-of-tau-ceremonies-with-optimistic-pipelining/6870/2)
- [KMSV21](https://eprint.iacr.org/2021/219.pdf) security proof for BGM17 and its optimization. Implementations:
- [Snarky](https://github.com/grnet/snarky) included in arkworks library.
### BGM17
BGM17 has two phase:
- Phase-1 - Powers of Tau: generic computation based on the number of circuit constraints
The Powers of Tau ceremony proceeds in turns, one turn for each participant… The result of each computation is then added to a public transcript, so that the entire protocol can be publicly verified. As long as one participant successfully destroys their randomness when they’re finished, the resulting parameters are secure. As more and more participants are added, it becomes unlikely that an adversary could have compromised everyone. This is especially true as participants have enormous flexibility in the counter-measures they employ.
- Phase 2: specific computation for the circuit.
#### Phase-1: Perpetual Power of Tau's
Perpetual Power of Tau's solution is to run a new phase-one ceremony for the entire community and thereby reduce the burden on all teams, including zk-SNARK scaling solutions (such as iden3 rollup, Matter Network, and Loopring) and mixers like Tornado Cash. Moreover, this ceremony will be perpetual — that is, there is no limit to the number of participants required, and any zk-SNARK project can pick any point of the ceremony to begin their circuit-specific second phase.

Each participant will receive a challenge file, and must generate a response file in a secure and honest manner. As long as one participant discards the toxic waste after this process, the entire ceremony can be trusted.
Each round takes about 24 hours on a fast machine, and requires a 97G download and 49G upload. We recognise that this is cumbersome for many, and is also significantly more time- and space-intensive than other Powers of Tau ceremonies. Yet, we want to support as many zk-SNARK circuits as possible, including those which a large number of constraints. In particular, roll_up requires more than 260 million constraints; as such, the ceremony must compute 2 ^ 28 powers of tau, which explains why it is so heavy.
There is a central coordinator (myself) who works with Kobi Gurkan and Barry WhiteHat to manage logistics, determine the order of participants, and maintain a record of all contributions. Although the coordinator has a great deal of influence over the process, they do not need to be fully trusted. Anyone can verify the public transcript of the ceremony, which is the whole set of challenge files, response files, and cryptographically signed attestations per participant. The coordinator, however, could censor participants, and the community should watch them to make sure that they do not.
Proects's Github repo is available [here](https://github.com/weijiekoh/perpetualpowersoftau).
#### Phase-2:
### Zkproof standardization recommendations for the ceremony:
**SRS generation using MPC**: In order to reduce the need of trust in a single entity generating
the SRS, it is possible to use a multi-party computation to generate the SRS. This method should
ideally be secure as long as one participant is honest (per independent computation phase). Some
considerations to strengthen the security of the MPC include:
- Have as many participants as possible
- Diversity of participants; reduce the chance they will collude
- Diversity of implementations (curve, MPC code, compiler, operating system, language)
- Diversity of hardware (CPU architecture, peripherals, RAM)
- One-time-use computers
- GCP / EC2 (leveraging enterprise security)
- If you are concerned about your hardware being compromised, then avoid side channels (power, audio/radio, surveillance)
- Hardware removal:
- Remove WiFi/Bluetooth chip
- Disconnect webcam / microphone / speakers
- Remove hard disks if not needed, or disable swap
- Air gaps
- Deterministic compilation
- Append-only logs
- Public verifiability of transcripts
- Scalability
- Handling aborts
- Reputation
- Information extraction from the hardware is difficult
- Flash drives with hardware read-only toggle
Some protocols (e.g., Powers of Tau) also require sampling unpredictable public randomness. Such
randomness can be harnessed from proof of work blockchains or other sources of entropy such
as stock markets. Verifiable Delay Functions can further reduce the ability to bias these sources
[BBBF18]
**SRS reusability**: For schemes that require an SRS, it may be possible to design an SRS generation
process that allows the re-usability of a part of the SRS, thus reducing the attack surface. A good
example of it is the Powers of Tau method for the Groth16 construction, where most of the SRS
can be reused before specializing to a specific constraint system.
### instructions for the participant
>https://docs.google.com/document/d/1GJwBAxZ3eEdcjPn4iSpKcWXXrl5YxWSMX8I0K2wiSsM/edit#
Zcash Sprout Multi-party Computation Instructions
Thank you for agreeing to participate in the Zcash “Sprout” multi-party computation.
Day 0 - Friday, October 21, 2016
Today you will purchase the equipment you need for the ceremony, and run a test on it to make sure it works.
What kind of hardware do I need?
Compute machine: Please purchase a desktop machine from a local computer store, at random. It must meet the following specifications:
a. 64-bit, ≥4 CPU cores (real cores, not counting hyperthreading)
b. ≥8GB of RAM
c. Have one built-in (internal SATA) DVD read/write drive. Do not attach any other drives to the machine.
d. You must be able to remove any wireless networking adapters attached to the device. In most commercial hardware today, a WiFi adapter is attached to the motherboard, and can be removed with a screwdriver. (This adapter is usually also a bluetooth adapter.)
e. You must be able to remove any hard disks or solid state drives from the machine by disconnecting their SATA connections to the motherboard.
Network machine: Re-use hardware you have if possible, but please ensure it has the following specifications:
a. 64-bit, 8GB of RAM
b. Have a DVD read/write drive, ideally built-in. If you use a portable USB drive and it fails, you may need to play with the command line on the machine to get it to work again due to security hardening policies. Please only have a single drive connected.
c. Ethernet connection for networking. Please have a reliable connection during the ceremony! Several gigabytes of data will be exchanged over the network.
Please purchase around 30 blank DVD-R/DVD+R discs for the ceremony, just to be safe. Ensure that they are DVD-R/DVD+R and not DVD-RW.
You will need two keyboards, and two mice just in case your BIOS requires a mouse to interact with it. You will need a monitor for each node, and ensure the monitors are compatible and you have cables/adapters to connect the monitors to the network node and compute node.
Download the software
Now, download the software that will be used for the ceremony:
Compute machine ISO: https://s3.amazonaws.com/iso-123876918270945/finalmpc2-compute.iso
(SHA256: 5f43aa1244a01b3cf9da4abeadde9e34b954a873565fc56b58c10780f3ce0e4c)
Network machine ISO: https://s3.amazonaws.com/iso-123876918270945/finalmpc2-network.iso
(SHA256: 375550be4c64ebc68a9306421bb71ad3556bc73f156a231503084f923900f4cb)
Burn these to DVD-R’s and boot the respective machine with them after they have been prepared and set up properly.
Optional:
You may also verify the integrity of the downloaded ISOs against Zcash’s offline master software signing key using gpg --verify. (signature #1) (signature #2) (key: 0x63C4A2169C1B2FA2)
Testing
Each machine will offer to run some diagnostics on the DVD drive after booting. Perform these diagnostics, if they work and the machines prompt you to press Enter to begin the ceremony, you can shut the machines down; you’re done for the day!
Day 1 - Saturday, October 22, 2016
Boot the machines up again with their respective ISOs and follow the on-screen instructions. Neither machine can be shut down after this point.
We will be available over Signal and on Google Hangouts during the ceremony.
It may take many hours for your network machine to receive disc A, and it may take some time for the compute machine to produce disc B. After your network machine has sent disc B and says “waiting to receive disc C” you can go to sleep.
Day 2 - Sunday, October 23, 2016
Follow the on-screen instructions to perform the rest of the steps. As with yesterday, wa