1+ use anyhow:: { Result , ensure} ;
2+ use binius_frontend:: {
3+ circuits:: semaphore_ecdsa:: {
4+ SemaphoreProofECDSA ,
5+ circuit:: IdentityECDSA ,
6+ MerkleTree ,
7+ } ,
8+ compiler:: { CircuitBuilder , circuit:: WitnessFiller } ,
9+ } ;
10+ use clap:: Args ;
11+
12+ use crate :: ExampleCircuit ;
13+
14+ /// Semaphore anonymous group membership proof with ECDSA key derivation
15+ pub struct SemaphoreExample {
16+ circuit : SemaphoreProofECDSA ,
17+ tree_height : usize ,
18+ message_len_bytes : usize ,
19+ scope_len_bytes : usize ,
20+ }
21+
22+ #[ derive( Args , Debug , Clone ) ]
23+ pub struct Params {
24+ /// Height of the Merkle tree (determines max group size = 2^height)
25+ #[ arg( long, default_value_t = 2 ) ]
26+ pub tree_height : usize ,
27+
28+ /// Maximum message length in bytes
29+ #[ arg( long, default_value_t = 32 ) ]
30+ pub message_len_bytes : usize ,
31+
32+ /// Maximum scope length in bytes
33+ #[ arg( long, default_value_t = 24 ) ]
34+ pub scope_len_bytes : usize ,
35+ }
36+
37+ #[ derive( Args , Debug , Clone ) ]
38+ pub struct Instance {
39+ /// Number of group members to create
40+ #[ arg( long, default_value_t = 4 ) ]
41+ pub group_size : usize ,
42+
43+ /// Index of the member generating the proof (0-based)
44+ #[ arg( long, default_value_t = 1 ) ]
45+ pub prover_index : usize ,
46+
47+ /// Message to include in the proof
48+ #[ arg( long, default_value = "I vote YES on proposal #42" ) ]
49+ pub message : String ,
50+
51+ /// Scope for this signal (prevents double-signaling within scope)
52+ #[ arg( long, default_value = "dao_vote_2024_q1" ) ]
53+ pub scope : String ,
54+ }
55+
56+ impl ExampleCircuit for SemaphoreExample {
57+ type Params = Params ;
58+ type Instance = Instance ;
59+
60+ fn build ( params : Params , builder : & mut CircuitBuilder ) -> Result < Self > {
61+ ensure ! ( params. tree_height > 0 , "Tree height must be > 0" ) ;
62+ ensure ! ( params. message_len_bytes > 0 , "Message length must be > 0" ) ;
63+ ensure ! ( params. scope_len_bytes > 0 , "Scope length must be > 0" ) ;
64+
65+ let circuit = SemaphoreProofECDSA :: new (
66+ builder,
67+ params. tree_height ,
68+ params. message_len_bytes ,
69+ params. scope_len_bytes ,
70+ ) ;
71+
72+ Ok ( Self {
73+ circuit,
74+ tree_height : params. tree_height ,
75+ message_len_bytes : params. message_len_bytes ,
76+ scope_len_bytes : params. scope_len_bytes ,
77+ } )
78+ }
79+
80+ fn populate_witness ( & self , instance : Instance , witness : & mut WitnessFiller ) -> Result < ( ) > {
81+ // Validate inputs
82+ ensure ! ( instance. group_size > 0 , "Group size must be > 0" ) ;
83+ ensure ! ( instance. prover_index < instance. group_size, "Prover index must be < group size" ) ;
84+ ensure ! ( instance. group_size <= ( 1 << self . tree_height) , "Group size exceeds tree capacity" ) ;
85+ ensure ! ( instance. message. len( ) <= self . message_len_bytes, "Message too long" ) ;
86+ ensure ! ( instance. scope. len( ) <= self . scope_len_bytes, "Scope too long" ) ;
87+
88+ // Create ECDSA identities
89+ let mut identities = Vec :: new ( ) ;
90+ for i in 0 ..instance. group_size {
91+ let secret_scalar = [ ( ( i + 42 ) as u8 ) ; 32 ] ;
92+ identities. push ( IdentityECDSA :: new ( secret_scalar) ) ;
93+ }
94+
95+ // Build Merkle tree
96+ let mut tree = MerkleTree :: new ( self . tree_height ) ;
97+ for identity in & identities {
98+ tree. add_leaf ( identity. commitment ( ) ) ;
99+ }
100+
101+ // Get proof for the prover
102+ let prover_identity = & identities[ instance. prover_index ] ;
103+ let merkle_proof = tree. proof ( instance. prover_index ) ;
104+
105+ // Populate witness
106+ self . circuit . populate_witness (
107+ witness,
108+ prover_identity,
109+ & merkle_proof,
110+ instance. message . as_bytes ( ) ,
111+ instance. scope . as_bytes ( ) ,
112+ ) ;
113+
114+ Ok ( ( ) )
115+ }
116+ }
117+
118+ #[ cfg( test) ]
119+ mod tests {
120+ use super :: * ;
121+ use binius_frontend:: circuits:: semaphore_ecdsa:: circuit:: IdentityECDSA ;
122+
123+ #[ test]
124+ fn test_examples_crate_identity_commitment ( ) {
125+ // Test the same computation from the examples crate
126+ let secret_scalar = [ 0x2b ; 32 ] ;
127+ println ! ( "Examples crate - Testing secret_scalar: {:02x?}" , secret_scalar) ;
128+
129+ let identity = IdentityECDSA :: new ( secret_scalar) ;
130+ let commitment = identity. commitment ( ) ;
131+ println ! ( "Examples crate - Direct commitment result: {:02x?}" , commitment) ;
132+
133+ // Let's see if this matches what the frontend crate produces
134+ }
135+ }
0 commit comments