semaphore_rs/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod circuit;
4mod field;
5pub mod hash;
6pub mod identity;
7pub mod packed_proof;
8pub mod poseidon_tree;
9pub mod protocol;
10
11pub use semaphore_rs_depth_config::get_supported_depths;
12
13// Export types
14pub use crate::field::{hash_to_field, Field, MODULUS};
15
16#[allow(dead_code)]
17#[cfg(test)]
18mod test {
19    use std::thread::spawn;
20
21    use semaphore_rs_depth_macros::test_all_depths;
22
23    use crate::identity::Identity;
24    use crate::poseidon_tree::LazyPoseidonTree;
25    use crate::protocol::{generate_nullifier_hash, generate_proof, verify_proof};
26    use crate::{hash_to_field, protocol, Field};
27
28    #[test]
29    fn test_field_serde() {
30        let value = Field::from(0x1234_5678);
31        let serialized = serde_json::to_value(value).unwrap();
32        let deserialized = serde_json::from_value(serialized).unwrap();
33        assert_eq!(value, deserialized);
34    }
35
36    fn test_end_to_end(
37        identity: &mut [u8],
38        external_nullifier: &[u8],
39        signal: &[u8],
40        depth: usize,
41    ) {
42        let leaf = Field::from(0);
43
44        // generate identity
45        let id = Identity::from_secret(identity, None);
46
47        // generate merkle tree
48        let mut tree = LazyPoseidonTree::new(depth, leaf).derived();
49        tree = tree.update(0, &id.commitment());
50
51        let merkle_proof = tree.proof(0);
52        let root = tree.root();
53
54        let signal_hash = hash_to_field(signal);
55        let external_nullifier_hash = hash_to_field(external_nullifier);
56        let nullifier_hash = generate_nullifier_hash(&id, external_nullifier_hash);
57
58        let proof =
59            generate_proof(&id, &merkle_proof, external_nullifier_hash, signal_hash).unwrap();
60
61        for _ in 0..5 {
62            let success = verify_proof(
63                root,
64                nullifier_hash,
65                signal_hash,
66                external_nullifier_hash,
67                &proof,
68                depth,
69            )
70            .unwrap();
71            assert!(success);
72        }
73    }
74
75    #[test_all_depths]
76    fn test_auth_flow(depth: usize) {
77        let mut secret = *b"oh so secret";
78        let id = Identity::from_secret(&mut secret[..], None);
79        let signal_hash = hash_to_field(b"signal");
80        let external_nullifier_hash = hash_to_field(b"appId");
81        let nullifier_hash = generate_nullifier_hash(&id, external_nullifier_hash);
82        let id_commitment = id.commitment();
83
84        let proof = protocol::authentication::generate_proof(
85            depth,
86            &id,
87            external_nullifier_hash,
88            signal_hash,
89        )
90        .unwrap();
91
92        let success = protocol::authentication::verify_proof(
93            depth,
94            id_commitment,
95            nullifier_hash,
96            signal_hash,
97            external_nullifier_hash,
98            &proof,
99        )
100        .unwrap();
101        assert!(success);
102    }
103
104    #[test_all_depths]
105    fn test_single(depth: usize) {
106        // Note that rust will still run tests in parallel
107        let mut hello = *b"hello";
108        test_end_to_end(&mut hello, b"appId", b"xxx", depth);
109    }
110
111    #[test_all_depths]
112    fn test_parallel(depth: usize) {
113        // Note that this does not guarantee a concurrency issue will be detected.
114        // For that we need much more sophisticated static analysis tooling like
115        // loom. See <https://github.com/tokio-rs/loom>
116        let mut a_id = *b"hello";
117        let mut b_id = *b"secret";
118        let a = spawn(move || test_end_to_end(&mut a_id, b"appId", b"xxx", depth));
119        let b = spawn(move || test_end_to_end(&mut b_id, b"test", b"signal", depth));
120        a.join().unwrap();
121        b.join().unwrap();
122    }
123}