pubscalareq.rs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. //! A module to look for, and apply, any statement involving the
  2. //! equality of _public_ `Scalar`s.
  3. //!
  4. //! Such a statement is of the form `a = 2*(c+1)` where `a` and `c` are
  5. //! public `Scalar`s. That is, it is a single variable name (which must
  6. //! be a public `Scalar`, as specified in the provided
  7. //! [`TaggedVarDict`]), an equal sign, and an [arithmetic expression]
  8. //! involving other public `Scalar` variables, constants, parens, and
  9. //! the operators `+`, `-`, and `*`.
  10. //!
  11. //! The statement is simply removed from the list of statements to be
  12. //! proven in the zero-knowledge sigma protocol, and code is emitted for
  13. //! the prover and verifier to each just check that the statement is
  14. //! satisfied.
  15. //!
  16. //! [arithmetic expression]: super::sigma::types::expr_type
  17. use super::codegen::CodeGen;
  18. use super::sigma::combiners::*;
  19. use super::sigma::types::{expr_type_tokens, AExprType};
  20. use super::syntax::{collect_cind_points, taggedvardict_to_vardict};
  21. use super::transform::prune_statement_tree;
  22. use super::{TaggedIdent, TaggedScalar, TaggedVarDict};
  23. use quote::quote;
  24. use syn::{parse_quote, Error, Expr, Result};
  25. /// Look for, and apply, all of the public scalar equality statements
  26. /// specified in leaves of the [`StatementTree`].
  27. #[allow(non_snake_case)] // so that Points can be capital letters
  28. pub fn transform(
  29. codegen: &mut CodeGen,
  30. st: &mut StatementTree,
  31. vars: &mut TaggedVarDict,
  32. ) -> Result<()> {
  33. // Construct the VarDict corresponding to vars
  34. let vardict = taggedvardict_to_vardict(vars);
  35. // A list of the computationally independent (non-vector) Points in
  36. // the macro input. There must be at least one of them in order to
  37. // handle public scalar equality statements inside disjunctions.
  38. let cind_points = collect_cind_points(vars);
  39. st.for_each_disjunction_branch(&mut |branch, path| {
  40. // Are we in the root disjunction branch? (path is empty)
  41. let in_root_disjunction_branch = path.is_empty();
  42. // For each leaf expression, see if it looks like a public Scalar
  43. // equality statement
  44. branch.for_each_disjunction_branch_leaf(&mut |leaf| {
  45. if let StatementTree::Leaf(Expr::Assign(syn::ExprAssign { left, right, .. })) = leaf {
  46. if let Expr::Path(syn::ExprPath { path, .. }) = left.as_ref() {
  47. if let Some(id) = path.get_ident() {
  48. let idstr = id.to_string();
  49. if let Some(TaggedIdent::Scalar(TaggedScalar {
  50. is_pub: true,
  51. is_vec: false,
  52. ..
  53. })) = vars.get(&idstr)
  54. {
  55. if let (
  56. AExprType::Scalar {
  57. is_pub: true,
  58. is_vec: false,
  59. ..
  60. },
  61. right_tokens,
  62. ) = expr_type_tokens(&vardict, right)?
  63. {
  64. // We found a public Scalar equality
  65. // statement.
  66. if in_root_disjunction_branch {
  67. // If we're in the root disjunction branch,
  68. // add code to both the prover and the
  69. // verifier to directly check the statement.
  70. codegen.prove_verify_append(quote! {
  71. if #id != #right_tokens {
  72. return Err(SigmaError::VerificationFailure);
  73. }
  74. });
  75. // Remove the statement from the
  76. // [`StatementTree`] by replacing it with
  77. // leaf_true (which will be pruned below).
  78. *leaf = StatementTree::leaf_true();
  79. } else {
  80. // If we're not in the root disjunction
  81. // branch, replace the statement
  82. // `left_id = right_side` with the
  83. // statement `left_id*A =
  84. // (right_side)*A` for a cind Point A.
  85. if cind_points.is_empty() {
  86. return Err(Error::new(
  87. proc_macro2::Span::call_site(),
  88. "At least one cind Point must be declared to support public Scalar equality statements inside disjunctions",
  89. ));
  90. }
  91. let cind_A = &cind_points[0];
  92. *leaf = StatementTree::Leaf(parse_quote! {
  93. #id * #cind_A = (#right) * #cind_A
  94. });
  95. }
  96. }
  97. }
  98. }
  99. }
  100. }
  101. Ok(())
  102. })
  103. })?;
  104. // Now prune the StatementTree
  105. prune_statement_tree(st);
  106. Ok(())
  107. }