dao-exec.zk 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. k = 13;
  2. field = "pallas";
  3. constant "DaoExec" {
  4. EcFixedPointShort VALUE_COMMIT_VALUE,
  5. EcFixedPoint VALUE_COMMIT_RANDOM,
  6. }
  7. witness "DaoExec" {
  8. # Proposal parameters
  9. Base proposal_dest_x,
  10. Base proposal_dest_y,
  11. Base proposal_amount,
  12. Base proposal_token_id,
  13. Base proposal_blind,
  14. # DAO parameters
  15. Base dao_proposer_limit,
  16. Base dao_quorum,
  17. Base dao_approval_ratio_quot,
  18. Base dao_approval_ratio_base,
  19. Base gov_token_id,
  20. Base dao_public_x,
  21. Base dao_public_y,
  22. Base dao_bulla_blind,
  23. # Votes
  24. Base yes_vote_value,
  25. Base all_vote_value,
  26. Scalar yes_vote_blind,
  27. Scalar all_vote_blind,
  28. # Outputs + Inputs
  29. Base user_serial,
  30. Base dao_serial,
  31. Base input_value,
  32. Scalar input_value_blind,
  33. # Miscellaneous
  34. Base dao_spend_hook,
  35. Base user_spend_hook,
  36. Base user_data,
  37. # Check input user_data_enc encodes the same DAO bulla
  38. Base input_user_data_blind,
  39. }
  40. circuit "DaoExec" {
  41. dao_bulla = poseidon_hash(
  42. dao_proposer_limit,
  43. dao_quorum,
  44. dao_approval_ratio_quot,
  45. dao_approval_ratio_base,
  46. gov_token_id,
  47. dao_public_x,
  48. dao_public_y,
  49. dao_bulla_blind,
  50. );
  51. # Proposal bulla being valid means DAO bulla is also valid because
  52. # dao-propose-main.zk already checks that when we first create the
  53. # proposal - so it is redundant here.
  54. proposal_bulla = poseidon_hash(
  55. proposal_dest_x,
  56. proposal_dest_y,
  57. proposal_amount,
  58. proposal_token_id,
  59. dao_bulla,
  60. proposal_blind,
  61. );
  62. constrain_instance(proposal_bulla);
  63. coin_0 = poseidon_hash(
  64. proposal_dest_x,
  65. proposal_dest_y,
  66. proposal_amount,
  67. proposal_token_id,
  68. user_serial,
  69. user_spend_hook,
  70. user_data,
  71. );
  72. constrain_instance(coin_0);
  73. change = base_sub(input_value, proposal_amount);
  74. coin_1 = poseidon_hash(
  75. dao_public_x,
  76. dao_public_y,
  77. change,
  78. proposal_token_id,
  79. dao_serial,
  80. dao_spend_hook,
  81. dao_bulla,
  82. );
  83. constrain_instance(coin_1);
  84. # Create Pedersen commitments for win_votes and total_votes, and
  85. # constrain the commitments' coordinates.
  86. yes_vote_value_c = ec_mul_short(yes_vote_value, VALUE_COMMIT_VALUE);
  87. yes_vote_blind_c = ec_mul(yes_vote_blind, VALUE_COMMIT_RANDOM);
  88. yes_vote_commit = ec_add(yes_vote_value_c, yes_vote_blind_c);
  89. constrain_instance(ec_get_x(yes_vote_commit));
  90. constrain_instance(ec_get_y(yes_vote_commit));
  91. all_vote_value_c = ec_mul_short(all_vote_value, VALUE_COMMIT_VALUE);
  92. all_vote_blind_c = ec_mul(all_vote_blind, VALUE_COMMIT_RANDOM);
  93. all_vote_commit = ec_add(all_vote_value_c, all_vote_blind_c);
  94. constrain_instance(ec_get_x(all_vote_commit));
  95. constrain_instance(ec_get_y(all_vote_commit));
  96. # Create Pedersen commitment for input_value and make public
  97. input_value_v = ec_mul_short(input_value, VALUE_COMMIT_VALUE);
  98. input_value_r = ec_mul(input_value_blind, VALUE_COMMIT_RANDOM);
  99. input_value_commit = ec_add(input_value_v, input_value_r);
  100. constrain_instance(ec_get_x(input_value_commit));
  101. constrain_instance(ec_get_y(input_value_commit));
  102. constrain_instance(dao_spend_hook);
  103. constrain_instance(user_spend_hook);
  104. constrain_instance(user_data);
  105. # Check that dao_quorum is less than or equal to all_vote_value
  106. one = witness_base(1);
  107. all_vote_value_1 = base_add(all_vote_value, one);
  108. less_than_strict(dao_quorum, all_vote_value_1);
  109. # approval_ratio_quot / approval_ratio_base <= yes_vote / all_vote
  110. #
  111. # The above is also equivalent to this:
  112. #
  113. # all_vote * approval_ratio_quot <= yes_vote * approval_ratio_base
  114. lhs = base_mul(all_vote_value, dao_approval_ratio_quot);
  115. rhs = base_mul(yes_vote_value, dao_approval_ratio_base);
  116. rhs_1 = base_add(rhs, one);
  117. less_than_strict(lhs, rhs_1);
  118. # Create coin 0
  119. # Create coin 1
  120. # Check values of coin 0 + coin 1 == input_value
  121. # Check value of coin 0 == proposal_amount
  122. # Check public key matches too
  123. # Create the input value commit
  124. # Create the value commits
  125. # The coin we are spending should have the encrypted DAO bulla
  126. # Make sure it is the same as the DAO we are operating on.
  127. input_user_data_enc = poseidon_hash(dao_bulla, input_user_data_blind);
  128. constrain_instance(input_user_data_enc);
  129. # NOTE: There is a vulnerability here where someone can create the exec
  130. # transaction with a bad note so it cannot be decrypted by the receiver
  131. # TODO: Research verifiable encryption inside ZK
  132. }