diff --git a/.gitignore b/.gitignore index c1b68b6..7857382 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.profraw .* Cargo.lock +snarkfiles_tmp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6e0a95f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "semaphore"] + path = semaphore + url = git@github.com:appliedzkp/semaphore.git diff --git a/README.md b/README.md index f8de3e7..f08fdb7 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,32 @@ -# Semaphore-rs +# 🦀 semaphore-rs -Rust support library for Semaphore +Rust support library for using [semaphore](https://github.com/appliedzkp/semaphore). It's mostly a Rust rewrite of [zk-kit](https://github.com/appliedzkp/zk-kit), but just focuses on semaphore (for now) and still covers a much smaller scope. It's using [ark-circom](https://github.com/gakonst/ark-circom) under the hood for generating the groth16 proofs. + +## Usage + +Add this line to your `cargo.toml`: +``` +semaphore = { git = "https://github.com/worldcoin/semaphore-rs" } +``` + +## Building semaphore circuits + +1. Check out submodule (if not done before already): `git submodule update --init --recursive` +1. Install semaphore dependencies `cd semaphore && npm install` +1. Compile circuits `ts-node ./scripts/compile-circuits.ts` +1. You'll find the `zkey` and `wasm` file in `semaphore/build/snark` ## Example +Example as in `src/lib.rs`, run with `cargo test`. + ```rust -use semaphore::{ - identity::Identity, hash::Hash, poseidon_tree::PoseidonTree, +use semaphore::{identity::Identity, hash::Hash, poseidon_tree::PoseidonTree, protocol::* }; use num_bigint::BigInt; // generate identity -let id = Identity::new(b"hello"); +let id = Identity::new(b"secret"); // generate merkle tree const LEAF: Hash = Hash::from_bytes_be([0u8; 32]); @@ -20,23 +35,23 @@ let mut tree = PoseidonTree::new(21, LEAF); let (_, leaf) = id.commitment().to_bytes_be(); tree.set(0, leaf.into()); -let root: BigInt = tree.root().into(); -dbg!(root); - let merkle_proof = tree.proof(0).expect("proof should exist"); -let root = tree.root().into(); +let root = tree.root(); // change signal and external_nullifier here -let signal = b"hello"; -let external_nullifier = b"123"; +let signal = b"xxx"; +let external_nullifier = b"appId"; -let nullifier_hash = generate_nullifier_hash(&id, external_nullifier); +let external_nullifier_hash = hash_external_nullifier(external_nullifier); +let nullifier_hash = generate_nullifier_hash(&id, &external_nullifier_hash); let config = SnarkFileConfig { - zkey: "./snarkfiles/semaphore.zkey".to_string(), - wasm: "./snarkfiles/semaphore.wasm".to_string(), + zkey: "./semaphore/build/snark/semaphore_final.zkey".to_string(), + wasm: "./semaphore/build/snark/semaphore.wasm".to_string(), }; -let proof = generate_proof(&config, &id, &merkle_proof, external_nullifier, signal).unwrap(); -let success = verify_proof(&config, &root, &nullifier_hash, signal, external_nullifier, &proof).unwrap(); +let proof = generate_proof(&config, &id, &merkle_proof, &external_nullifier_hash, signal).unwrap(); +let success = verify_proof(&config, &root.into(), &nullifier_hash, signal, &external_nullifier_hash, &proof).unwrap(); + +assert!(success); ``` diff --git a/semaphore b/semaphore new file mode 160000 index 0000000..5186a94 --- /dev/null +++ b/semaphore @@ -0,0 +1 @@ +Subproject commit 5186a940ff495ff163bd5779631a716d0bf96507 diff --git a/snarkfiles/semaphore.wasm b/snarkfiles/semaphore.wasm deleted file mode 100644 index 495dbf0..0000000 Binary files a/snarkfiles/semaphore.wasm and /dev/null differ diff --git a/snarkfiles/semaphore.zkey b/snarkfiles/semaphore.zkey deleted file mode 100644 index df83946..0000000 Binary files a/snarkfiles/semaphore.zkey and /dev/null differ diff --git a/src/lib.rs b/src/lib.rs index c1d5b4e..fff3375 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,21 +52,23 @@ mod test { let signal = b"xxx"; let external_nullifier = b"appId"; - let nullifier_hash = generate_nullifier_hash(&id, external_nullifier); + let external_nullifier_hash = hash_external_nullifier(external_nullifier); + let nullifier_hash = generate_nullifier_hash(&id, &external_nullifier_hash); let config = SnarkFileConfig { - zkey: "./snarkfiles/semaphore.zkey".to_string(), - wasm: "./snarkfiles/semaphore.wasm".to_string(), + zkey: "./semaphore/build/snark/semaphore_final.zkey".to_string(), + wasm: "./semaphore/build/snark/semaphore.wasm".to_string(), }; let proof = - generate_proof(&config, &id, &merkle_proof, external_nullifier, signal).unwrap(); + generate_proof(&config, &id, &merkle_proof, &external_nullifier_hash, signal).unwrap(); + let success = verify_proof( &config, &root.into(), &nullifier_hash, signal, - external_nullifier, + &external_nullifier_hash, &proof, ) .unwrap(); diff --git a/src/protocol.rs b/src/protocol.rs index a1759d0..c692745 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -57,7 +57,10 @@ pub fn hash_external_nullifier(nullifier: &[u8]) -> BigInt { pub fn generate_nullifier_hash(identity: &Identity, external_nullifier: &[u8]) -> BigInt { let res = POSEIDON .hash(vec![ - bigint_to_fr(&hash_external_nullifier(external_nullifier)), + bigint_to_fr(&BigInt::from_bytes_be( + Sign::Plus, + external_nullifier, + )), bigint_to_fr(&identity.nullifier), ]) .expect("hash with fixed input size can't fail"); @@ -94,21 +97,21 @@ pub fn generate_proof( let inputs = { let mut inputs: HashMap> = HashMap::new(); - inputs.insert("identity_nullifier".to_string(), vec![identity + inputs.insert("identityNullifier".to_string(), vec![identity .nullifier .clone()]); - inputs.insert("identity_trapdoor".to_string(), vec![identity + inputs.insert("identityTrapdoor".to_string(), vec![identity .trapdoor .clone()]); - inputs.insert("identity_path_index".to_string(), merkle_proof.path_index()); + inputs.insert("treePathIndices".to_string(), merkle_proof.path_index()); inputs.insert( - "path_elements".to_string(), + "treeSiblings".to_string(), merkle_proof_to_vec(merkle_proof), ); - inputs.insert("external_nullifier".to_string(), vec![ - hash_external_nullifier(external_nullifier), + inputs.insert("externalNullifier".to_string(), vec![ + BigInt::from_bytes_be(Sign::Plus, external_nullifier), ]); - inputs.insert("signal_hash".to_string(), vec![hash_signal(signal)]); + inputs.insert("signalHash".to_string(), vec![hash_signal(signal)]); inputs }; @@ -174,7 +177,7 @@ pub fn verify_proof( .expect("can not be negative"), ), Fp256::from( - hash_external_nullifier(external_nullifier) + BigInt::from_bytes_be(Sign::Plus, external_nullifier) .to_biguint() .expect("can not be negative"), ),