pubscalareq.rs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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: l_is_vec,
  52. ..
  53. })) = vars.get(&idstr)
  54. {
  55. if let (
  56. AExprType::Scalar {
  57. is_pub: true,
  58. is_vec: r_is_vec,
  59. ..
  60. },
  61. right_tokens,
  62. ) = expr_type_tokens(&vardict, right)?
  63. {
  64. if *l_is_vec != r_is_vec {
  65. return Err(Error::new(
  66. proc_macro2::Span::call_site(),
  67. "Only one side of the public equality statement is a vector",
  68. ));
  69. }
  70. // We found a public Scalar equality
  71. // statement.
  72. if in_root_disjunction_branch {
  73. // If we're in the root disjunction branch,
  74. // add code to both the prover and the
  75. // verifier to directly check the statement.
  76. codegen.prove_verify_append(quote! {
  77. if #id != #right_tokens {
  78. return Err(InvalidInstance::new(concat!(
  79. "public scalar equality does not hold: ",
  80. stringify!(#id),
  81. )).into());
  82. }
  83. });
  84. // Remove the statement from the
  85. // [`StatementTree`] by replacing it with
  86. // leaf_true (which will be pruned below).
  87. *leaf = StatementTree::leaf_true();
  88. } else {
  89. // If we're not in the root disjunction
  90. // branch, replace the statement
  91. // `left_id = right_side` with the
  92. // statement `left_id*A =
  93. // (right_side)*A` for a cind Point A.
  94. if cind_points.is_empty() {
  95. return Err(Error::new(
  96. proc_macro2::Span::call_site(),
  97. "At least one cind Point must be declared to support public Scalar equality statements inside disjunctions",
  98. ));
  99. }
  100. let cind_A = &cind_points[0];
  101. *leaf = StatementTree::Leaf(parse_quote! {
  102. #id * #cind_A = (#right) * #cind_A
  103. });
  104. }
  105. }
  106. }
  107. }
  108. }
  109. }
  110. Ok(())
  111. })
  112. })?;
  113. // Now prune the StatementTree
  114. prune_statement_tree(st);
  115. Ok(())
  116. }