rsnark_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Data, DeriveInput, Fields, Visibility, parse_macro_input};
4
5/// Circuit derive macro
6///
7/// Automatically generates CircuitElement implementation and related helper code
8/// for the annotated struct.
9///
10/// Usage:
11/// ```rust
12/// #[derive(Circuit)]
13/// pub struct MyCircuit {
14///     a: u32,        // private field -> PrivateCircuitElement
15///     pub b: u32,    // public field -> PublicCircuitElement  
16/// }
17/// ```
18#[proc_macro_derive(Circuit)]
19pub fn circuit_derive(input: TokenStream) -> TokenStream {
20    let input = parse_macro_input!(input as DeriveInput);
21
22    match generate_circuit_impl(&input) {
23        Ok(tokens) => tokens,
24        Err(err) => err.to_compile_error().into(),
25    }
26}
27
28fn generate_circuit_impl(input: &DeriveInput) -> syn::Result<TokenStream> {
29    let name = &input.ident;
30    let name_str = name.to_string().to_lowercase();
31
32    // Generate module name: __rsnark_generated_{name}
33    let module_name = format_ident!("__rsnark_generated_{}", name_str);
34
35    // Generate CircuitDefine struct name: {Name}CircuitDefine
36    let define_name = format_ident!("{}CircuitDefine", name);
37
38    // Generate PublicWitness struct name: {Name}PublicWitness
39    let public_witness_name = format_ident!("{}PublicWitness", name);
40
41    // Parse struct fields
42    let fields = match &input.data {
43        Data::Struct(data) => match &data.fields {
44            Fields::Named(fields) => &fields.named,
45            _ => {
46                return Err(syn::Error::new_spanned(
47                    input,
48                    "Only named fields are supported",
49                ));
50            }
51        },
52        _ => return Err(syn::Error::new_spanned(input, "Only structs are supported")),
53    };
54
55    // Separate public and private fields
56    let mut private_fields = Vec::new();
57    let mut public_fields = Vec::new();
58
59    for field in fields {
60        let field_name = field.ident.as_ref().unwrap();
61        let field_type = &field.ty;
62
63        match &field.vis {
64            Visibility::Public(_) => {
65                public_fields.push((field_name, field_type));
66            }
67            _ => {
68                private_fields.push((field_name, field_type));
69            }
70        }
71    }
72
73    // Generate fields for CircuitDefine struct
74    let define_fields = fields.iter().map(|field| {
75        let field_name = field.ident.as_ref().unwrap();
76        let field_type = &field.ty;
77
78        match &field.vis {
79            Visibility::Public(_) => {
80                quote! {
81                    pub #field_name: ::rsnark_core::PublicCircuitElement<#field_type>
82                }
83            }
84            _ => {
85                quote! {
86                    pub #field_name: ::rsnark_core::PrivateCircuitElement<#field_type>
87                }
88            }
89        }
90    });
91
92    // Generate field initialization in new method
93    let new_field_inits = fields.iter().map(|field| {
94        let field_name = field.ident.as_ref().unwrap();
95        let field_type = &field.ty;
96
97        match &field.vis {
98            Visibility::Public(_) => {
99                quote! {
100                    let #field_name = #field_type::create_public(initer, is_private);
101                }
102            }
103            _ => {
104                quote! {
105                    let #field_name = #field_type::create_private(initer);
106                }
107            }
108        }
109    });
110
111    let field_names: Vec<_> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();
112
113    // Generate append_public method implementation for original struct
114    let append_public_impl_orig = public_fields.iter().map(|(field_name, _)| {
115        quote! {
116            self.#field_name.append_public_witness(witness, false);
117        }
118    });
119
120    // Generate append_public method implementation for PublicWitness struct
121    let append_public_impl_witness = public_fields.iter().map(|(field_name, _)| {
122        quote! {
123            self.#field_name.append_public_witness(witness, false);
124        }
125    });
126
127    // Generate append_witness method implementation for all fields
128    let append_witness_impl = fields.iter().map(|field| {
129        let field_name = field.ident.as_ref().unwrap();
130
131        match &field.vis {
132            Visibility::Public(_) => {
133                // Public fields: is_private = false
134                quote! {
135                    self.#field_name.append_witness(public, private, false || _is_private);
136                }
137            }
138            _ => {
139                // Private fields: is_private = true
140                quote! {
141                    self.#field_name.append_witness(public, private, true);
142                }
143            }
144        }
145    });
146
147    // Generate public witness fields for into_public_witness method
148    let public_witness_fields = public_fields.iter().map(|(field_name, _)| {
149        quote! {
150            #field_name: self.#field_name.into_public_witness()
151        }
152    });
153
154    // Generate PublicWitness struct fields
155    let public_witness_struct_fields = public_fields.iter().map(|(field_name, field_type)| {
156        quote! {
157            pub #field_name: ::rsnark_core::PublicWitness<#field_type>
158        }
159    });
160
161    let expanded = quote! {
162        mod #module_name {
163            use super::*;
164
165            use ::rsnark_core::{
166                CircuitWitness, CircuitPublicWitness, U256, VariableIniter,
167            };
168
169            impl CircuitWitness for #name {
170                type PrivateElement = #define_name;
171                type PublicElement = #define_name;
172                type PublicWitness = #public_witness_name;
173
174                fn create_public(initer: &mut VariableIniter, is_private: bool) -> Self::PublicElement {
175                    #define_name::new(initer, is_private)
176                }
177
178                fn create_private(initer: &mut VariableIniter) -> Self::PrivateElement {
179                    #define_name::new(initer, true)
180                }
181
182                fn append_witness(&self, public: &mut Vec<U256>, private: &mut Vec<U256>, _is_private: bool) {
183                    #(#append_witness_impl)*
184                }
185
186                fn into_public_witness(self) -> Self::PublicWitness {
187                    #public_witness_name {
188                        #(#public_witness_fields,)*
189                    }
190                }
191            }
192
193            #[doc(hidden)]
194            pub struct #define_name {
195                #(#define_fields,)*
196            }
197
198            impl #define_name {
199                fn new(initer: &mut VariableIniter, is_private: bool) -> Self {
200                    #(#new_field_inits)*
201
202                    Self {
203                        #(#field_names,)*
204                    }
205                }
206            }
207
208            impl CircuitPublicWitness for #name {
209                fn append_public_witness(&self, witness: &mut Vec<U256>, _is_private: bool) {
210                    #(#append_public_impl_orig)*
211                }
212            }
213
214            #[doc(hidden)]
215            pub struct #public_witness_name {
216                #(#public_witness_struct_fields,)*
217            }
218
219            impl CircuitPublicWitness for #public_witness_name {
220                fn append_public_witness(&self, witness: &mut Vec<U256>, _is_private: bool) {
221                    #(#append_public_impl_witness)*
222                }
223            }
224        }
225    };
226
227    Ok(TokenStream::from(expanded))
228}