1use super::sigma::codegen::{StructField, StructFieldList};
5use super::syntax::*;
6use proc_macro2::TokenStream;
7use quote::{format_ident, quote};
8#[cfg(test)]
9use syn::parse_quote;
10use syn::Ident;
11
12pub struct CodeGen {
21 proto_name: Ident,
24 group_name: Ident,
27 vars: TaggedVarDict,
30 unique_prefix: String,
33 sent_instance: StructFieldList,
38 prove_code: TokenStream,
40 verify_code: TokenStream,
42 verify_pre_instance_code: TokenStream,
46}
47
48impl CodeGen {
49 fn unique_prefix(vars: &TaggedVarDict) -> String {
52 'outer: for tag in 0usize.. {
53 let try_prefix = if tag == 0 {
54 "gen__".to_string()
55 } else {
56 format!("gen{}__", tag)
57 };
58 for v in vars.keys() {
59 if v.starts_with(&try_prefix) {
60 continue 'outer;
61 }
62 }
63 return try_prefix;
64 }
65 String::new()
69 }
70
71 pub fn new(spec: &SigmaCompSpec) -> Self {
74 Self {
75 proto_name: spec.proto_name.clone(),
76 group_name: spec.group_name.clone(),
77 vars: spec.vars.clone(),
78 unique_prefix: Self::unique_prefix(&spec.vars),
79 sent_instance: StructFieldList::default(),
80 prove_code: quote! {},
81 verify_code: quote! {},
82 verify_pre_instance_code: quote! {},
83 }
84 }
85
86 #[cfg(test)]
87 pub fn new_empty() -> Self {
89 Self {
90 proto_name: parse_quote! { proto },
91 group_name: parse_quote! { G },
92 vars: TaggedVarDict::default(),
93 unique_prefix: "gen__".into(),
94 sent_instance: StructFieldList::default(),
95 prove_code: quote! {},
96 verify_code: quote! {},
97 verify_pre_instance_code: quote! {},
98 }
99 }
100
101 pub fn gen_scalar(
109 &self,
110 vars: &mut TaggedVarDict,
111 base: &Ident,
112 is_rand: bool,
113 is_vec: bool,
114 ) -> Ident {
115 let id = format_ident!("{}{}", self.unique_prefix, base);
116 vars.insert(
117 id.to_string(),
118 TaggedIdent::Scalar(TaggedScalar {
119 id: id.clone(),
120 is_pub: false,
121 is_rand,
122 is_vec,
123 }),
124 );
125 id
126 }
127
128 pub fn gen_point(
142 &mut self,
143 vars: &mut TaggedVarDict,
144 base: &Ident,
145 is_vec: bool,
146 send_to_verifier: bool,
147 ) -> Ident {
148 let id = format_ident!("{}{}", self.unique_prefix, base);
149 vars.insert(
150 id.to_string(),
151 TaggedIdent::Point(TaggedPoint {
152 id: id.clone(),
153 is_cind: false,
154 is_const: false,
155 is_vec,
156 }),
157 );
158 if send_to_verifier {
159 if is_vec {
160 self.sent_instance.push_vecpoint(&id);
161 } else {
162 self.sent_instance.push_point(&id);
163 }
164 }
165 id
166 }
167
168 pub fn gen_ident(&self, base: &Ident) -> Ident {
170 format_ident!("{}{}", self.unique_prefix, base)
171 }
172
173 pub fn prove_append(&mut self, code: TokenStream) {
175 let prove_code = &self.prove_code;
176 self.prove_code = quote! {
177 #prove_code
178 #code
179 };
180 }
181
182 pub fn verify_append(&mut self, code: TokenStream) {
184 let verify_code = &self.verify_code;
185 self.verify_code = quote! {
186 #verify_code
187 #code
188 };
189 }
190
191 pub fn verify_pre_instance_append(&mut self, code: TokenStream) {
194 let verify_pre_instance_code = &self.verify_pre_instance_code;
195 self.verify_pre_instance_code = quote! {
196 #verify_pre_instance_code
197 #code
198 };
199 }
200
201 pub fn prove_verify_append(&mut self, code: TokenStream) {
204 let prove_code = &self.prove_code;
205 self.prove_code = quote! {
206 #prove_code
207 #code
208 };
209 let verify_code = &self.verify_code;
210 self.verify_code = quote! {
211 #verify_code
212 #code
213 };
214 }
215
216 pub fn prove_verify_pre_instance_append(&mut self, code: TokenStream) {
220 let prove_code = &self.prove_code;
221 self.prove_code = quote! {
222 #prove_code
223 #code
224 };
225 let verify_pre_instance_code = &self.verify_pre_instance_code;
226 self.verify_pre_instance_code = quote! {
227 #verify_pre_instance_code
228 #code
229 };
230 }
231
232 pub fn code_strings(&self) -> (String, String, String) {
237 (
238 self.prove_code.to_string(),
239 self.verify_code.to_string(),
240 self.verify_pre_instance_code.to_string(),
241 )
242 }
243
244 pub fn generate(
249 &self,
250 spec: &mut SigmaCompSpec,
251 emit_prover: bool,
252 emit_verifier: bool,
253 ) -> TokenStream {
254 let proto_name = &self.proto_name;
255 let group_name = &self.group_name;
256
257 let group_types = quote! {
258 use super::group;
259 pub type Scalar = <super::#group_name as group::Group>::Scalar;
260 pub type Point = super::#group_name;
261 };
262
263 let vardict = taggedvardict_to_vardict(&self.vars);
266 let sigma_proofs_vardict = taggedvardict_to_vardict(&spec.vars);
271
272 let mut sigma_proofs_codegen = super::sigma::codegen::CodeGen::new(
274 format_ident!("sigma"),
275 format_ident!("Point"),
276 &sigma_proofs_vardict,
277 &mut spec.statements,
278 );
279 let sigma_proofs_code = sigma_proofs_codegen.generate(emit_prover, emit_verifier);
280
281 let mut pub_instance_fields = StructFieldList::default();
282 pub_instance_fields.push_vars(&vardict, true);
283 let mut witness_fields = StructFieldList::default();
284 witness_fields.push_vars(&vardict, false);
285
286 let mut sigma_proofs_instance_fields = StructFieldList::default();
287 sigma_proofs_instance_fields.push_vars(&sigma_proofs_vardict, true);
288 let mut sigma_proofs_witness_fields = StructFieldList::default();
289 sigma_proofs_witness_fields.push_vars(&sigma_proofs_vardict, false);
290
291 let instance_def = {
293 let decls = pub_instance_fields.field_decls();
294 #[cfg(feature = "dump")]
295 let dump_impl = {
296 let dump_chunks = pub_instance_fields.dump(&format_ident!("fmt"));
297 quote! {
298 impl Instance {
299 fn dump_scalar(s: &Scalar, fmt: &mut std::fmt::Formatter<'_>) {
300 let bytes: &[u8] = &s.to_repr();
301 for b in bytes.iter().rev() {
302 write!(fmt, "{:02x}", b).ok();
306 }
307 }
308
309 fn dump_point(p: &Point, fmt: &mut std::fmt::Formatter<'_>) {
310 let bytes: &[u8] = &p.to_bytes();
311 for b in bytes.iter().rev() {
312 write!(fmt, "{:02x}", b).ok();
316 }
317 }
318 }
319
320 impl std::fmt::Debug for Instance {
321 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
322 #dump_chunks
323 Ok(())
324 }
325 }
326 }
327 };
328 #[cfg(not(feature = "dump"))]
329 let dump_impl = {
330 quote! {}
331 };
332 quote! {
333 #[derive(Clone)]
334 pub struct Instance {
335 #decls
336 }
337
338 #dump_impl
339 }
340 };
341
342 let witness_def = if emit_prover {
344 let decls = witness_fields.field_decls();
345 quote! {
346 #[derive(Clone)]
347 pub struct Witness {
348 #decls
349 }
350 }
351 } else {
352 quote! {}
353 };
354
355 let prove_func = if emit_prover {
357 let instance_ids = pub_instance_fields.field_list();
358 let witness_ids = witness_fields.field_list();
359 let sigma_proofs_instance_ids = sigma_proofs_instance_fields.field_list();
360 let sigma_proofs_witness_ids = sigma_proofs_witness_fields.field_list();
361 let prove_code = &self.prove_code;
362 let codegen_instance_var = format_ident!("{}sigma_instance", self.unique_prefix);
363 let codegen_witness_var = format_ident!("{}sigma_witness", self.unique_prefix);
364 let instance_var = format_ident!("{}instance", self.unique_prefix);
365 let witness_var = format_ident!("{}witness", self.unique_prefix);
366 let rng_var = format_ident!("{}rng", self.unique_prefix);
367 let proof_var = format_ident!("{}proof", self.unique_prefix);
368 let sid_var = format_ident!("{}session_id", self.unique_prefix);
369 let sent_instance_code = {
370 let chunks = self.sent_instance.fields.iter().map(|sf| match sf {
371 StructField::Point(id) => quote! {
372 #proof_var.extend(sigma_proofs::serialization::serialize_elements(
373 std::slice::from_ref(&#codegen_instance_var.#id)
374 ));
375 },
376 StructField::VecPoint(id) => quote! {
377 #proof_var.extend(sigma_proofs::serialization::serialize_elements(
378 &#codegen_instance_var.#id
379 ));
380 },
381 _ => quote! {},
382 });
383 quote! { #(#chunks)* }
384 };
385
386 let dumper = if cfg!(feature = "dump") {
387 quote! {
388 sigma_compiler::dumper::dump(
389 &format!("{} sigma_compiler prover instance = {{\n{:?}}}\n",
390 stringify!(#proto_name), #instance_var));
391 }
392 } else {
393 quote! {}
394 };
395
396 let sigma_dumper = if cfg!(feature = "dump") {
397 quote! {
398 sigma_compiler::dumper::dump(
399 &format!("{} sigma prover instance = {{\n{:?}}}\n",
400 stringify!(#proto_name), #codegen_instance_var));
401 }
402 } else {
403 quote! {}
404 };
405
406 quote! {
407 pub fn prove(
408 #instance_var: &Instance,
409 #witness_var: &Witness,
410 #sid_var: &[u8],
411 #rng_var: &mut (impl CryptoRng + RngCore),
412 ) -> Result<Vec<u8>, SigmaError> {
413 #dumper
414 let Instance { #instance_ids } = #instance_var.clone();
415 let Witness { #witness_ids } = #witness_var.clone();
416 #prove_code
417 let mut #proof_var = Vec::<u8>::new();
418 let #codegen_instance_var = sigma::Instance {
419 #sigma_proofs_instance_ids
420 };
421 let #codegen_witness_var = sigma::Witness {
422 #sigma_proofs_witness_ids
423 };
424 #sent_instance_code
425 #sigma_dumper
426 #proof_var.extend(
427 sigma::prove(
428 &#codegen_instance_var,
429 &#codegen_witness_var,
430 #sid_var,
431 #rng_var,
432 )?
433 );
434 Ok(#proof_var)
435 }
436 }
437 } else {
438 quote! {}
439 };
440
441 let verify_func = if emit_verifier {
443 let instance_ids = pub_instance_fields.field_list();
444 let sigma_proofs_instance_ids = sigma_proofs_instance_fields.field_list();
445 let verify_pre_instance_code = &self.verify_pre_instance_code;
446 let verify_code = &self.verify_code;
447 let codegen_instance_var = format_ident!("{}sigma_instance", self.unique_prefix);
448 let element_len_var = format_ident!("{}element_len", self.unique_prefix);
449 let offset_var = format_ident!("{}proof_offset", self.unique_prefix);
450 let instance_var = format_ident!("{}instance", self.unique_prefix);
451 let proof_var = format_ident!("{}proof", self.unique_prefix);
452 let sid_var = format_ident!("{}session_id", self.unique_prefix);
453 let sent_instance_code = {
454 let element_len_code = if self.sent_instance.fields.is_empty() {
455 quote! {}
456 } else {
457 quote! {
458 let #element_len_var =
459 <Point as group::GroupEncoding>::Repr::default().as_ref().len();
460 }
461 };
462
463 let chunks = self.sent_instance.fields.iter().map(|sf| match sf {
464 StructField::Point(id) => quote! {
465 let #id: Point = sigma_proofs::serialization::deserialize_elements(
466 &#proof_var[#offset_var..],
467 1,
468 ).ok_or(SigmaError::VerificationFailure)?[0];
469 #offset_var += #element_len_var;
470 },
471 StructField::VecPoint(id) => quote! {
472 #id = sigma_proofs::serialization::deserialize_elements(
473 &#proof_var[#offset_var..],
474 #id.len(),
475 ).ok_or(SigmaError::VerificationFailure)?;
476 #offset_var += #element_len_var * #id.len();
477 },
478 _ => quote! {},
479 });
480
481 quote! {
482 let mut #offset_var = 0usize;
483 #element_len_code
484 #(#chunks)*
485 }
486 };
487
488 let dumper = if cfg!(feature = "dump") {
489 quote! {
490 sigma_compiler::dumper::dump(
491 &format!("{} sigma_compiler verifier instance = {{\n{:?}}}\n",
492 stringify!(#proto_name), #instance_var));
493 }
494 } else {
495 quote! {}
496 };
497
498 let sigma_dumper = if cfg!(feature = "dump") {
499 quote! {
500 sigma_compiler::dumper::dump(
501 &format!("{} sigma verifier instance = {{\n{:?}}}\n",
502 stringify!(#proto_name), #codegen_instance_var));
503 }
504 } else {
505 quote! {}
506 };
507
508 quote! {
509 pub fn verify(
510 #instance_var: &Instance,
511 #proof_var: &[u8],
512 #sid_var: &[u8],
513 ) -> Result<(), SigmaError> {
514 #dumper
515 let Instance { #instance_ids } = #instance_var.clone();
516 #verify_pre_instance_code
517 #sent_instance_code
518 #verify_code
519 let #codegen_instance_var = sigma::Instance {
520 #sigma_proofs_instance_ids
521 };
522 #sigma_dumper
523 sigma::verify(
524 &#codegen_instance_var,
525 &#proof_var[#offset_var..],
526 #sid_var,
527 )
528 }
529 }
530 } else {
531 quote! {}
532 };
533
534 let dump_use = if cfg!(feature = "dump") {
536 quote! {
537 use group::GroupEncoding;
538 }
539 } else {
540 quote! {}
541 };
542 quote! {
543 #[allow(non_snake_case)]
544 pub mod #proto_name {
545 use super::sigma_compiler;
546 use sigma_compiler::group::Group;
547 use sigma_compiler::group::ff::{Field, PrimeField};
548 use sigma_compiler::group::ff::derive::subtle::ConditionallySelectable;
549 use sigma_compiler::rand::{CryptoRng, RngCore};
550 use sigma_compiler::sigma_proofs;
551 use sigma_compiler::sigma_proofs::errors::Error as SigmaError;
552 use sigma_compiler::vecutils::*;
553 use std::ops::Neg;
554 #dump_use
555
556 #group_types
557
558 #sigma_proofs_code
559
560 #instance_def
561 #witness_def
562 #prove_func
563 #verify_func
564 }
565 }
566 }
567}