Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: test rust client for gnark prover #484

Merged
merged 4 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
uses: actions/checkout@v4
with:
lfs: true
submodules: true

- name: Cache .local directory
uses: buildjet/cache@v3
Expand All @@ -45,6 +46,15 @@ jobs:
./scripts/install.sh
source ./scripts/devenv.sh

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version-file: './gnark-prover/go.mod'
- name: Build
run: |
cd gnark-prover
go build

- name: Build and test
run: |
source ./scripts/devenv.sh
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "gnark-prover"]
path = gnark-prover
url = [email protected]:Lightprotocol/gnark-prover.git
49 changes: 47 additions & 2 deletions Cargo.lock

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

20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ Developers can use Light to build applications such as
- on-chain games with encrypted game state
- zk-identity



## ZK Anchor

ZK Anchor is what we call the collection of developer tools for writing Private Solana Programs (PSPs).
Expand All @@ -34,6 +32,20 @@ To get started, a good PSP reference implementation is available [here](https://

Otherwise, to work with this Monorepo, read below:

## Git Large File Storage (LFS)
This project uses Git LFS to manage and version large files. Before you can clone the project and fetch all the necessary data, you need to install and configure Git LFS on your machine.

If you already have Git installed, run the following command:
```
git lfs install
```

To verify that Git LFS is properly configured, use:
```
git lfs env
```

The output should show that Git LFS is installed and configured correctly. After setting up Git LFS, you can proceed to clone the project.

## Development environment

Expand Down Expand Up @@ -96,6 +108,10 @@ If you still want to setup dependencies manually, these are the requirements:
* [NodeJS](https://nodejs.org/) [(16.16 LTS)](https://nodejs.org/en/blog/release/v16.16.0)
* [Anchor](https://www.anchor-lang.com/) [(0.26.0)](https://crates.io/crates/anchor-cli/0.26.0)

## Initializing Submodules
Before building, make sure to initialize the submodules:
```git submodule update --init```

## Building

To build the project, use the following commands:
Expand Down
2 changes: 1 addition & 1 deletion circuit-lib/circuit-lib.circom/scripts/buildMerkle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ for ((i=1; i<=MAX_COUNT; i++)); do
execute_commands "$MERKLE_TREE_HEIGHT" "$i" "$POWERS_OF_TAU" || exit
done

execute_commands "$MERKLE_TREE_HEIGHT" 8 "$POWERS_OF_TAU" || exit
execute_commands "$MERKLE_TREE_HEIGHT" 8 "$POWERS_OF_TAU" || exit
3 changes: 3 additions & 0 deletions circuit-lib/circuit-lib.js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"scripts": {
"test": "ts-mocha --resolveJsonModule ./tsconfig.json -t 100000000 tests/**/*.ts --exit",
"test-merkle": "ts-mocha --resolveJsonModule ./tsconfig.json -t 100000000 tests/merkle-tree.test.ts --exit",
"test-gnark": "pnpm gnark-prover && ts-mocha --resolveJsonModule ./tsconfig.json -t 100000000 tests/gnark.test.ts --exit",
"gnark-prover": "./scripts/prover.sh",
"format": "prettier --write \"tests/**/*.{ts,js}\" \"src/**/*.{ts,js}\"",
"lint": "pnpm prettier \"tests/**/*.{ts,js}\" \"src/**/*.{ts,js}\" --check",
"build": "rimraf lib && pnpm tsc"
Expand All @@ -25,6 +27,7 @@
"@types/chai-as-promised": "^7.1.6",
"@types/mocha": "^10.0.3",
"@types/node-fetch": "^2.6.2",
"axios": "^1.5.0",
"chai": "^4.3.10",
"chai-as-promised": "^7.1.1",
"circom_tester": "^0.0.19",
Expand Down
20 changes: 20 additions & 0 deletions circuit-lib/circuit-lib.js/scripts/prover.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash

killall light-prover

# Get the root directory of the Git repository
root_dir=$(git rev-parse --show-toplevel)

# Change the directory to 'gnark-prover' within the Git root directory
# shellcheck disable=SC2164
cd "$root_dir/gnark-prover"

# If 'gnark-prover' directory does not exist, print error and exit
if [ $? -ne 0 ]; then
echo "Directory gnark-prover does not exist in the Git root directory. Run \`git submodule update --init\` to fetch the submodule."
exit 1
fi

go build
# Execute 'go run main.go start'
./light-prover start &
73 changes: 73 additions & 0 deletions circuit-lib/circuit-lib.js/tests/gnark.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { MerkleTree } from "../src";
import { LightWasm, WasmFactory } from "@lightprotocol/account.rs";
import axios from "axios";
import { BN } from "@coral-xyz/anchor";
import { assert } from "chai";

describe("Tests", () => {
let lightWasm: LightWasm;
const MAX_RETRIES = 20;
const DELAY_MS = 5000;
const SERVER_URL = "http://localhost:3001";
const PROVE_URL = `${SERVER_URL}/prove`;
const HEALTH_CHECK_URL = `${SERVER_URL}/health`;

async function pingServer(serverUrl: string) {
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
try {
const response = await axios.get(serverUrl);
if (response.status === 200) {
console.log("Server is up!");
break;
}
} catch (error) {
console.log(
`Attempt ${attempt + 1} failed. Retrying in ${
DELAY_MS / 1000
} seconds...`,
);
}
await new Promise((res) => setTimeout(res, DELAY_MS)); // Wait before retrying
}
}

before(async () => {
lightWasm = await WasmFactory.getInstance();
});

it("merkle proofgen", async () => {
await pingServer(HEALTH_CHECK_URL);

const hasher = await WasmFactory.getInstance();
const merkleHeights = [26];
const utxos = [1, 2, 3, 4, 8];
for (let i = 0; i < merkleHeights.length; i++) {
for (let j = 0; j < utxos.length; j++) {
const leaf = hasher.poseidonHashString(["1"]);
const merkleTree = new MerkleTree(merkleHeights[i], hasher, [leaf]);

const pathEements: string[] = merkleTree.path(
merkleTree.indexOf(leaf),
).pathElements;
const hexPathElements = pathEements.map((value) => toHex(value));
let inputs = {
root: new Array(utxos[j]).fill(toHex(merkleTree.root())),
inPathIndices: new Array(utxos[j]).fill(merkleTree.indexOf(leaf)),
inPathElements: new Array(utxos[j]).fill(hexPathElements),
leaf: new Array(utxos[j]).fill(toHex(leaf)),
};
const inputsData = JSON.stringify(inputs);
console.time(`Proof generation for ${merkleHeights[i]} ${utxos[j]}`);
const response = await axios.post(PROVE_URL, inputsData);
console.timeEnd(`Proof generation for ${merkleHeights[i]} ${utxos[j]}`);

assert.equal(response.status, 200);
assert.isNotEmpty(response.data.toString());
}
}
});

function toHex(bnString: string) {
return "0x" + new BN(bnString).toString(16);
}
});
8 changes: 8 additions & 0 deletions circuit-lib/circuitlib-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@ log = "0.4"
env_logger = "0.10.2"
# 1.3.0 required by package `aes-gcm-siv v0.10.3`
zeroize = "=1.3.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.60"
num-traits = "0.2.18"

[dev-dependencies]
tokio = { version = "1.36.0", features = ["rt", "macros"] }
reqwest = { version = "0.11.24", features = ["json", "rustls-tls"] }
duct = "0.13.7"
1 change: 1 addition & 0 deletions circuit-lib/circuitlib-rs/scripts/prover.sh
9 changes: 9 additions & 0 deletions circuit-lib/circuitlib-rs/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use env_logger::Builder;
use log::LevelFilter;

pub fn change_endianness(bytes: &[u8]) -> Vec<u8> {
let mut vec = Vec::new();
for b in bytes.chunks(32) {
Expand All @@ -13,3 +16,9 @@ pub fn convert_endianness_128(bytes: &[u8]) -> Vec<u8> {
.flat_map(|b| b.iter().copied().rev().collect::<Vec<u8>>())
.collect::<Vec<u8>>()
}

pub fn init_logger() {
let _ = Builder::new()
.filter_module("circuitlib_rs", LevelFilter::Info)
.try_init();
}
1 change: 1 addition & 0 deletions circuit-lib/circuitlib-rs/src/merkle_proof_inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub fn public_inputs(merkle_proof_inputs: &[MerkleTreeProofInput]) -> Vec<[u8; 3
}

pub struct ProofInputs<'a>(pub &'a [MerkleTreeProofInput]);

impl<'a> TryInto<HashMap<String, Inputs>> for ProofInputs<'a> {
type Error = std::io::Error;

Expand Down
3 changes: 3 additions & 0 deletions circuit-lib/circuitlib-rs/tests/gnark/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub const SERVER_ADDRESS: &str = "http://localhost:3001";
pub const HEALTH_CHECK: &str = "/health";
pub const PROVE: &str = "/prove";
Loading
Loading