Skip to content

Feat/implement proof gen #7

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

Merged
merged 10 commits into from
Apr 21, 2025
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
3,439 changes: 3,203 additions & 236 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ blake = "2.0.2"
light-poseidon = "0.3.0"
num-bigint = "0.4.6"
thiserror = "2.0.12"
ruint = "1.14.0"
num-traits = "0.2.19"
ethers-core = "2.0.14"
anyhow = "1.0.97"
reqwest = { version = "0.12.15", features = ["blocking", "json"] }
tokio = { version = "1", features = ["full"] }

# arkworks
ark-ec = { version = "=0.5.0", default-features = false }
Expand All @@ -21,10 +27,18 @@ zk-kit-lean-imt = { git = "https://github.com/brech1/zk-kit.rust", package = "zk
serde = { version = "1", features = ["derive"], optional = true }
serde_json = { version = "1", optional = true }

# circom-prover
rust-witness = "0.1"
circom-prover = "=0.1.1"

[features]
default = []
default = ["serde"]
serde = [
"dep:serde",
"serde_json",
"zk-kit-lean-imt/serde"
]

[build-dependencies]
rust-witness = "0.1"
reqwest = { version = "0.12.15", features = ["blocking", "json"] }
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,19 @@

All tasks related to the Semaphore Rust implementation are public. You can track their progress, statuses, and additional details in the [Semaphore Rust view](https://github.com/orgs/semaphore-protocol/projects/10/views/29).



## 🛠 Install

Clone this repository:

```bash
git clone git@github.com:semaphore-protocol/semaphore-rs.git
```

Semaphore uses `Circom-Prover` to generate zero-knowledge proofs for `Circom` circuits. Since `Circom-Prover` generates the witness function at build time, developers must specify the Merkle tree depth during compilation. This can be done by setting the `SEMAPHORE_DEPTH` environment variable:

```bash
cd semaphore-rs
SEMAPHORE_DEPTH=<tree depth> cargo build
```
66 changes: 66 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use reqwest::blocking::Client;
use std::error::Error;
use std::fs::{File, create_dir_all};
use std::io::copy;
use std::path::{Path, PathBuf};

/// download semaphore artifacts by required tree depth
fn download_semaphore_artifacts(depth: usize) -> Result<(), Box<dyn Error>> {
let base_url = "https://snark-artifacts.pse.dev/semaphore/latest/";
let remote_filenames = [
format!("semaphore-{}.wasm", depth),
format!("semaphore-{}.zkey", depth),
];
let local_filenames = ["semaphore.wasm", "semaphore.zkey"];

let client = Client::new();
let target_dir = Path::new("./zkey");

// Verify if those files have been downloaded or not. Skip downloading if yes.
let version_path = target_dir.join("depth");
if version_path.exists() {
let current_version = std::fs::read_to_string(&version_path)?.trim().to_string();
if current_version == depth.to_string() {
println!(
"Artifacts for depth {} already downloaded, skipping.",
depth
);
return Ok(());
}
}
// create ./zkey folder
create_dir_all(target_dir)?;

// download artifacts
for (remote, local) in remote_filenames.iter().zip(local_filenames.iter()) {
let url = format!("{}{}", base_url, remote);
let dest_path: PathBuf = target_dir.join(local);

eprintln!("Downloading {}...", url);
let mut resp = client.get(&url).send()?.error_for_status()?;
let mut out = File::create(&dest_path)?;
copy(&mut resp, &mut out)?;
eprintln!("Saved as {}", dest_path.display());
}

// update depth info
std::fs::write(&version_path, depth.to_string())?;

Ok(())
}

fn main() {
// Default depth is 10 for testing purposes; can be overridden via SEMAPHORE_DEPTH environment variable
let depth: usize = std::env::var("SEMAPHORE_DEPTH")
.unwrap_or_else(|_| "10".to_string())
.parse()
.expect("SEMAPHORE_DEPTH must be a valid usize");

if depth > 32 {
panic!("The tree depth must be less than 32.");
}

download_semaphore_artifacts(depth).expect("Failed to download artifacts");

rust_witness::transpile::transpile_wasm("./zkey".to_string());
}
12 changes: 6 additions & 6 deletions src/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use ark_ff::{BigInteger, PrimeField};
use light_poseidon::{Poseidon, PoseidonHasher};
use zk_kit_lean_imt::{
hashed_tree::{HashedLeanIMT, LeanIMTHasher},
lean_imt::MerkleProof,
lean_imt,
};

/// Size of nodes and leaves in bytes
Expand All @@ -21,6 +21,9 @@ pub const EMPTY_ELEMENT: Element = [0u8; ELEMENT_SIZE];
/// Element type alias
pub type Element = [u8; ELEMENT_SIZE];

/// Merkle proof alias
pub type MerkleProof = lean_imt::MerkleProof<ELEMENT_SIZE>;

/// Poseidon LeanIMT hasher
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct PoseidonHash;
Expand Down Expand Up @@ -140,17 +143,14 @@ impl Group {
}

/// Creates a proof of membership for a member
pub fn generate_proof(
&self,
index: usize,
) -> Result<MerkleProof<ELEMENT_SIZE>, SemaphoreError> {
pub fn generate_proof(&self, index: usize) -> Result<MerkleProof, SemaphoreError> {
self.tree
.generate_proof(index)
.map_err(SemaphoreError::LeanIMTError)
}

/// Verifies a proof of membership for a member
pub fn verify_proof(proof: &MerkleProof<ELEMENT_SIZE>) -> bool {
pub fn verify_proof(proof: &MerkleProof) -> bool {
HashedLeanIMT::<ELEMENT_SIZE, PoseidonHash>::verify_proof(proof)
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ pub mod group;
pub mod identity;
pub mod proof;
pub mod utils;

pub const MIN_TREE_DEPTH: u16 = 1;
pub const MAX_TREE_DEPTH: u16 = 32;
Loading
Loading