Skip to content

Commit

Permalink
MerkleSumTree version improvements (#230)
Browse files Browse the repository at this point in the history
Co-authored-by: sifnoc <[email protected]>
Co-authored-by: Alex Kuzmin <[email protected]>
Co-authored-by: ntampakas <[email protected]>
  • Loading branch information
4 people authored Dec 15, 2023
1 parent 7489c53 commit 8dca58b
Show file tree
Hide file tree
Showing 94 changed files with 22,819 additions and 62,170 deletions.
18 changes: 18 additions & 0 deletions .github/scripts/wakeup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
set -e

runner="i-0e04845bff4576909"

while true; do
runner_status=$(aws ec2 describe-instances --instance-ids $runner --query "Reservations[*].Instances[*].State.[Name]" --output text)
if [ $runner_status = "stopped" ]; then
aws ec2 start-instances --instance-ids $runner
break
elif [ $runner_status = "running" ]; then
break
else
sleep 5
fi
done

exit 0
40 changes: 34 additions & 6 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,43 @@ on:
pull_request:
branches: ["*"]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
build:
wakeup:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read

steps:
- uses: actions/checkout@v3

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::490752553772:role/summa-solvency-ec2-slc
role-duration-seconds: 900
aws-region: us-west-2

- name: Wakeup runner
run: .github/scripts/wakeup.sh

build:
runs-on: [summa-solvency-runner]
needs: [wakeup]

steps:
- uses: actions/checkout@v3

- name: Set Environment
run: echo "PATH=/home/ubuntu/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> "$GITHUB_ENV"

- name: Install solc
run: (hash svm 2>/dev/null || cargo install --version 0.2.23 svm-rs) && svm install 0.8.20 && solc --version

Expand All @@ -24,23 +51,24 @@ jobs:
cd zk_prover
cargo test --release --features dev-graph -- --nocapture
- name: Test Nova Prover
- name: Test Zk Prover examples
run: |
cd zk_prover
cargo run --release --example gen_inclusion_verifier
cargo run --release --example gen_commitment
cargo run --release --example gen_inclusion_proof
cargo run --release --example nova_incremental_verifier
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Test backend
env:
SIGNATURE_VERIFICATION_MESSAGE: "Summa proof of solvency for CryptoExchange"
run: |
cd backend
cargo test --release -- --nocapture
- name: Test example
- name: Test backend example
run: |
cd backend
cargo run --release --example summa_solvency_flow
1 change: 1 addition & 0 deletions backend/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ futures = "0.3.28"
num-bigint = "0.4.3"
serde = { version = "1.0.166", features = ["derive"] }
snark-verifier-sdk = { git = "https://github.com/privacy-scaling-explorations/snark-verifier", version = "0.1.1" }
ethers = { version = "2.0.7", default-features = false, features = ["ethers-solc"] }
ethers = { version = "2.0.7", default-features = false, features = ["ethers-solc", "legacy"] }
reqwest = { version = "0.11", features = ["json"] }
serde_json = "1.0.64"
tokio = { version = "1.7.1", features = ["full"] }
base64 = "0.13"
bincode = "1.3.3"
num-traits = "0.2.14"

[build-dependencies]
ethers = { version = "2.0.7", default-features = false, features = ["ethers-solc"] }
ethers = { version = "2.0.7", default-features = false, features = ["ethers-solc", "legacy"] }
66 changes: 27 additions & 39 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@ This directory contains the backend implementation for the Summa Proof of Solven

### Round

The `Round` component represents a specific period or cycle in the Summa Proof of Solvency protocol. It encapsulates the state of the system at a given time, including the snapshot of assets and liabilities, as well as the associated proofs.
The `Round` struct integrates with the `Snapshot` and `SummaSigner` to facilitate the generation and submission of proofs to the contract.
The `Round` component represents a specific period or cycle in the Summa Proof of Solvency protocol. It encapsulates the state of the system at a given time, including the snapshot of assets and liabilities, as well as the associated proofs.
The `Round` struct integrates with the `Snapshot` and `SummaSigner` to facilitate the generation and submission of proofs to the contract.

Key Features:

- Initialization of a new round with specific parameters.
- Building a snapshot of the current state.
- Dispatching solvency proofs to the contract.
- Submitting commitment to the contract.
- Retrieving proofs of inclusion for specific users.

### AddressOwnership

The `AddressOwnership` component is responsible for managing and verifying the ownership of addresses. It ensures that addresses used in the protocol owned by the respective participants. This component interacts with the `SummaSigner` to submit proofs of address ownership to on-chain.

Key Features:

- Initialization with specific signer details.
- Dispatching proofs of address ownership to the contract.

Expand All @@ -41,26 +43,26 @@ To build the binary executable and test it

```
cargo build
SIGNATURE_VERIFICATION_MESSAGE="Summa proof of solvency for CryptoExchange" cargo test --release -- --nocapture
cargo test --release -- --nocapture
```

## Important Notices

### Generating and updating verifier contracts for Backend
### Generating and updating verifier contract for Backend

The verifier contract in the backend were generated using a predefined set of parameters: `N_CURRENCIES = 2` and `N_BYTES=14`, as indicated [here](https://github.com/summa-dev/summa-solvency/blob/master/zk_prover/examples/gen_inclusion_verifier.rs#L21-L22).
If you intend to work with different parameters, you'll need to adjust these hard-coded values and then generate new verifier contract.

The verifier contracts in the backend were generated using a predefined set of parameters: `N_ASSETS = 2` and `N_BYTES=14`, as indicated [here](https://github.com/summa-dev/summa-solvency/blob/master/zk_prover/examples/gen_solvency_verifier.rs#L21-L22).
If you intend to work with different parameters, you'll need to adjust these hard-coded values and then generate new verifier contracts.

The process described below assists in both generating the verifiers and updating the Summa contract, which integrates the new verifiers as constructors.
The process described below assists in both generating the verifier and updating the Summa contract, which integrates the new verifier as constructors.

#### Using the Bash Script

We have provided a bash script to automate the process of updating the verifier contracts and the Summa contract. To use the script:
We have provided a bash script to automate the process of updating the verifier contract and the Summa contract. To use the script:

Ensure you have the necessary permissions to execute the script.

```
backend $ chmod +x scripts/update_verifier_contracts.sh
backend $ scripts/update_verifier_contract.sh
```

## Summa solvency flow example
Expand Down Expand Up @@ -91,26 +93,19 @@ If executed successfully, you'll see:
1. Ownership proofs are submitted successfully!
```

### 2. Submit Commitment

### 2. Submit Proof of Solvency
The CEX must submit a commitment to the Summa contract for each round. This commitment consists of a `timestamp`, the root hash of the Merkle Sum Tree (`mst_root`), and `balances`.

This step is also crucial for two primary reasons:

first, to validate the root hash of the Merkle Sum Tree (`mst_root`); and second, to ensure that the assets held by the CEX exceed their liabilities, as confirmed through the proof verification on the Summa contract.
The CEX must submit this proof of solvency to the Summa contract.
Without publishing the commitment, users cannot verify their inclusion proof on the Summa contract. This is because the inclusion verifier function internally requires the `mst_root`, but users only know the `timestamp` associated with the round and the verifier functions does not requre `mst_root` directly.

Currently, it's a mandatory requirement to provide this proof before generating the inclusion proof for each user in the current round.

Without this verification, It seems the user may not trust to the inclusion proof for the round. becuase the `mst_root` is not published on contract. More specifically, it means that the `mst_root` is not correctly verified on the Summa contract.

In here, we'll introduce you through the process of submitting a solvency proof using the `Round` to the Summa contract.
In here, we'll introduce you through the process of submitting a commitment using the `Round` to the Summa contract.
The Round serves as the core of the backend in Summa, and we have briefly described it in the Components section.

To initialize the `Round` instance, you'll need paths to specific CSV files (`assets.csv` and `entry_16.csv`) and the `ptau/hermez-raw-11` file. Here's what each file does:
To initialize the `Round` instance, you'll need paths to the liabilities CSV file (`entry_16.csv`) and the `ptau/hermez-raw-11` file. The files serve the following purpose:

- `assets.csv`: Calculates the total balance of assets for the solvency proof. Only the CEX can generate this file.
- `entry_16.csv`: Used to build the Merkle sum tree, with each leaf element derived from sixteen entries in the CSV.
- `ptau/hermez-raw-11`: Contains parameters for constructing the zk circuits.
- `entry_16.csv`: contains the username and liabilities entries for each CEX user (necessary to build the commitment). Liabilities column names have the following format: `balance_<CRYPTOCURRENCY>_<CHAIN>`, where <CRYPTOCURRENCY> and <CHAIN> are the names of the cryptocurrencies and their corresponding blockchains. <CHAIN> values are the same as in the Address Ownership Proof step;
- `ptau/hermez-raw-11`: contains parameters for constructing the zk circuits.

Using the `Round` instance, the solvency proof is dispatched to the Summa contract with the `dispatch_solvency_proof` method.

Expand Down Expand Up @@ -138,27 +133,20 @@ This is the final step in the Summa process and the only part that occurs on the

Users receive the proof for a specific round and use methods available on the deployed Summa contract. Importantly, the Summa contract verifier function is a view function, meaning it doesn't consume gas or change the blockchain's state.

In this step, you'll see:
In this step, the user has to:

- Retrieve the `mst_root` from the Summa contract and match it with the `root_hash` in the proof.
- Ensure the `leaf_hash` aligns with the hash based on the `username` and `balances` provided by the CEX.
- Use the `verify_inclusion_proof` method on the Summa contract to validate the proof.
- Ensure the `leaf_hash` (public input of the proof) aligns with the Poseidon hash of the `username` and `balances` provided by the CEX.
- Submit the proof to the `verify_inclusion_proof` method on the Summa contract Which will:
- Retrieve the `mstRoot` from the Summa contract and match it with the `root_hash` in the proof.
- Retrieve the `rootBalances` from the Summa contract and match it with the `root_balances` in the proof
- Verify the zk Proof

The result will display as:

```
4. Verifying the proof on contract verifier for User #0: true
```

### 4. Verify Proof of Inclusion

This is the final step in the Summa process and the only part that occurs on the user side. Users receive the proof for a specific round and use methods available on the deployed Summa contract. Importantly, the Summa contract verifier function is a view function, meaning it doesn't consume gas or change the blockchain's state.

In this step, you'll see:
- Retrieve the `mst_root` from the Summa contract and match it with the `root_hash` in the proof.
- Ensure the `leaf_hash` aligns with the hash based on the `username` and `balances` provided by the CEX.
- Use the `verify_inclusion_proof` method on the Summa contract to validate the proof.
The result will display as:

**Note:** In a production environment, users can independently verify their proof using public interfaces, such as Etherscan, as shown below:
![Summa contract interface on Etherscan](summa_verifier_interface.png)
This offers an added layer of transparency and trust.
5 changes: 0 additions & 5 deletions backend/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ fn main() {
"Summa",
"Summa",
),
(
"src/contracts/generated/solvency_verifier.rs",
"SolvencyVerifier",
"SolvencyVerifier",
),
(
"src/contracts/generated/inclusion_verifier.rs",
"InclusionVerifier",
Expand Down
48 changes: 26 additions & 22 deletions backend/examples/summa_solvency_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ use serde_json::{from_reader, to_string_pretty};
use summa_backend::{
apis::{
address_ownership::AddressOwnership,
leaf_hash_from_inputs,
round::{MstInclusionProof, Round},
},
contracts::signer::{AddressInput, SummaSigner},
tests::initialize_test_env,
};
use summa_solvency::merkle_sum_tree::utils::generate_leaf_hash;
use summa_solvency::merkle_sum_tree::MerkleSumTree;

const N_ASSETS: usize = 2;
const N_CURRENCIES: usize = 2;
const USER_INDEX: usize = 0;

#[tokio::main]
Expand All @@ -24,21 +25,25 @@ async fn main() -> Result<(), Box<dyn Error>> {

// 1. Submit ownership proof
//
// Each CEX prepares its own `signature` CSV file.
let signature_csv_path = "src/apis/csv/signatures.csv";

// The signer instance would be shared with `address_ownership` and `round` instances
//
// Using AddressInput::Address to directly provide the summa_contract's address.
// For deployed contracts, if the address is stored in a config file,
// you can alternatively use AddressInput::Path to specify the file's path.
// Using `AddressInput::Address`` to directly provide the summa_contract's address.
//
// If the address of a deployed contract is stored in a configuration file,
// you can use `AddressInput::Path` to provide the path to that file.
//
// For example, if the contract address is in "backend/src/contracts/deployments.json" located
// you would use `AddressInput::Path` as follows:`AddressInput::Path("backend/src/contracts/deployments.json".to_string())`.
//
let signer = SummaSigner::new(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
anvil.endpoint().as_str(),
AddressInput::Address(summa_contract.address()),
)
.await?;

// Each CEX prepares its own `signature` CSV file.
let signature_csv_path = "../csv/signatures.csv";
let mut address_ownership_client = AddressOwnership::new(&signer, signature_csv_path).unwrap();

// Dispatch the proof of address ownership.
Expand All @@ -49,22 +54,21 @@ async fn main() -> Result<(), Box<dyn Error>> {

println!("1. Ownership proofs are submitted successfully!");

// 2. Submit solvency proof
// 2. Submit Commitment
//
// Initialize the `Round` instance to submit the proof of solvency.
let asset_csv = "src/apis/csv/assets.csv";
let entry_csv = "../zk_prover/src/merkle_sum_tree/csv/entry_16.csv";
// Initialize the `Round` instance to submit the liability commitment.
let params_path = "ptau/hermez-raw-11";
let entry_csv = "../csv/entry_16.csv";
let mst = MerkleSumTree::from_csv(entry_csv).unwrap();

// Using the `round` instance, the solvency proof is dispatched to the Summa contract with the `dispatch_solvency_proof` method.
// Using the `round` instance, the commitment is dispatched to the Summa contract with the `dispatch_commitment` method.
let timestamp = 1u64;
let mut round =
Round::<4, 2, 14>::new(&signer, entry_csv, asset_csv, params_path, timestamp).unwrap();
let mut round = Round::<4, 2, 14>::new(&signer, Box::new(mst), params_path, timestamp).unwrap();

// Sends the solvency proof, which should ideally complete without errors.
round.dispatch_solvency_proof().await?;
// Sends the commitment, which should ideally complete without errors.
round.dispatch_commitment().await?;

println!("2. Solvency proof is submitted successfully!");
println!("2. Commitment is submitted successfully!");

// 3. Generate Inclusion Proof
//
Expand Down Expand Up @@ -100,19 +104,19 @@ async fn main() -> Result<(), Box<dyn Error>> {
// It's assumed that both `user_name` and `balances` are provided by the CEX.
// The `balances` represent the user's balances on the CEX at `snapshot_time`.
let user_name = "dxGaEAii".to_string();
let balances = vec![11888, 41163];
let balances = vec!["11888".to_string(), "41163".to_string()];

let leaf_hash = public_inputs[0];
assert_eq!(
leaf_hash,
generate_leaf_hash::<N_ASSETS>(user_name.clone(), balances.clone())
leaf_hash_from_inputs::<N_CURRENCIES>(user_name.clone(), balances.clone())
);

// Get `mst_root` from contract. the `mst_root` is disptached by CEX with specific time `snapshot_time`.
let mst_root = summa_contract.mst_roots(snapshot_time).call().await?;
let commitment = summa_contract.commitments(snapshot_time).call().await?;

// Match the `mst_root` with the `root_hash` derived from the proof.
assert_eq!(mst_root, public_inputs[1]);
assert_eq!(commitment, public_inputs[1]);

// Validate the inclusion proof using the contract verifier.
let proof = inclusion_proof.get_proof();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ set -e
echo "1. Building verifier contracts"
cd ../zk_prover
cargo run --release --example gen_inclusion_verifier
cargo run --release --example gen_solvency_verifier

# Generate Commitment for Merkle Sum Tree
echo "2. Generate Commitment for Merkle Sum Tree"
cd ../zk_prover
cargo run --release --example gen_commitment

# Deploy contracts to local environment
echo "2. Deploying contracts to local environment"
echo "3. Deploying contracts to local environment"
cd ../contracts
npm install
npx hardhat node &
Expand All @@ -17,7 +21,7 @@ sleep 5
npx hardhat run scripts/deploy.ts --network localhost

# Generate interface files for Backend
echo "3. Generating interface files for Backend"
echo "4. Generating interface files for Backend"
cd ../backend
cargo build

Expand Down
3 changes: 0 additions & 3 deletions backend/src/apis/csv/assets.csv

This file was deleted.

Loading

0 comments on commit 8dca58b

Please sign in to comment.