wallet.rs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. use log::debug;
  2. use rand::rngs::OsRng;
  3. use halo2_proofs::circuit::Value;
  4. use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas};
  5. use darkfi::{
  6. crypto::{
  7. keypair::SecretKey,
  8. util::{pedersen_commitment_u64, poseidon_hash},
  9. Proof,
  10. },
  11. zk::vm::{Witness, ZkCircuit},
  12. };
  13. use crate::{
  14. contract::dao_contract::{
  15. exec::validate::CallData, mint::wallet::DaoParams, propose::wallet::Proposal, CONTRACT_ID,
  16. },
  17. util::{FuncCall, ZkContractInfo, ZkContractTable},
  18. };
  19. pub struct Builder {
  20. pub proposal: Proposal,
  21. pub dao: DaoParams,
  22. pub yes_votes_value: u64,
  23. pub all_votes_value: u64,
  24. pub yes_votes_blind: pallas::Scalar,
  25. pub all_votes_blind: pallas::Scalar,
  26. pub user_serial: pallas::Base,
  27. pub user_coin_blind: pallas::Base,
  28. pub dao_serial: pallas::Base,
  29. pub dao_coin_blind: pallas::Base,
  30. pub input_value: u64,
  31. pub input_value_blind: pallas::Scalar,
  32. pub hook_dao_exec: pallas::Base,
  33. pub signature_secret: SecretKey,
  34. }
  35. impl Builder {
  36. pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall {
  37. debug!(target: "dao_contract::exec::wallet::Builder", "build()");
  38. debug!(target: "dao_contract::exec::wallet", "proposalserial{:?}", self.proposal.serial);
  39. let mut proofs = vec![];
  40. let proposal_dest_coords = self.proposal.dest.0.to_affine().coordinates().unwrap();
  41. let proposal_amount = pallas::Base::from(self.proposal.amount);
  42. let dao_proposer_limit = pallas::Base::from(self.dao.proposer_limit);
  43. let dao_quorum = pallas::Base::from(self.dao.quorum);
  44. let dao_approval_ratio_quot = pallas::Base::from(self.dao.approval_ratio_quot);
  45. let dao_approval_ratio_base = pallas::Base::from(self.dao.approval_ratio_base);
  46. let dao_pubkey_coords = self.dao.public_key.0.to_affine().coordinates().unwrap();
  47. let user_spend_hook = pallas::Base::from(0);
  48. let user_data = pallas::Base::from(0);
  49. let input_value = pallas::Base::from(self.input_value);
  50. let change = input_value - proposal_amount;
  51. let dao_bulla = poseidon_hash::<8>([
  52. dao_proposer_limit,
  53. dao_quorum,
  54. dao_approval_ratio_quot,
  55. dao_approval_ratio_base,
  56. self.dao.gov_token_id,
  57. *dao_pubkey_coords.x(),
  58. *dao_pubkey_coords.y(),
  59. self.dao.bulla_blind,
  60. ]);
  61. let proposal_bulla = poseidon_hash::<8>([
  62. *proposal_dest_coords.x(),
  63. *proposal_dest_coords.y(),
  64. proposal_amount,
  65. self.proposal.serial,
  66. self.proposal.token_id,
  67. dao_bulla,
  68. self.proposal.blind,
  69. // @tmp-workaround
  70. self.proposal.blind,
  71. ]);
  72. let coin_0 = poseidon_hash::<8>([
  73. *proposal_dest_coords.x(),
  74. *proposal_dest_coords.y(),
  75. proposal_amount,
  76. self.proposal.token_id,
  77. self.proposal.serial,
  78. user_spend_hook,
  79. user_data,
  80. self.proposal.blind,
  81. ]);
  82. let coin_1 = poseidon_hash::<8>([
  83. *dao_pubkey_coords.x(),
  84. *dao_pubkey_coords.y(),
  85. change,
  86. self.proposal.token_id,
  87. self.dao_serial,
  88. self.hook_dao_exec,
  89. proposal_bulla,
  90. self.dao_coin_blind,
  91. ]);
  92. let yes_votes_commit = pedersen_commitment_u64(self.yes_votes_value, self.yes_votes_blind);
  93. let yes_votes_commit_coords = yes_votes_commit.to_affine().coordinates().unwrap();
  94. let all_votes_commit = pedersen_commitment_u64(self.all_votes_value, self.all_votes_blind);
  95. let all_votes_commit_coords = all_votes_commit.to_affine().coordinates().unwrap();
  96. let input_value_commit = pedersen_commitment_u64(self.input_value, self.input_value_blind);
  97. let input_value_commit_coords = input_value_commit.to_affine().coordinates().unwrap();
  98. let zk_info = zk_bins.lookup(&"dao-exec".to_string()).unwrap();
  99. let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
  100. info
  101. } else {
  102. panic!("Not binary info")
  103. };
  104. let zk_bin = zk_info.bincode.clone();
  105. let prover_witnesses = vec![
  106. // proposal params
  107. Witness::Base(Value::known(*proposal_dest_coords.x())),
  108. Witness::Base(Value::known(*proposal_dest_coords.y())),
  109. Witness::Base(Value::known(proposal_amount)),
  110. Witness::Base(Value::known(self.proposal.serial)),
  111. Witness::Base(Value::known(self.proposal.token_id)),
  112. Witness::Base(Value::known(self.proposal.blind)),
  113. // DAO params
  114. Witness::Base(Value::known(dao_proposer_limit)),
  115. Witness::Base(Value::known(dao_quorum)),
  116. Witness::Base(Value::known(dao_approval_ratio_quot)),
  117. Witness::Base(Value::known(dao_approval_ratio_base)),
  118. Witness::Base(Value::known(self.dao.gov_token_id)),
  119. Witness::Base(Value::known(*dao_pubkey_coords.x())),
  120. Witness::Base(Value::known(*dao_pubkey_coords.y())),
  121. Witness::Base(Value::known(self.dao.bulla_blind)),
  122. // votes
  123. Witness::Base(Value::known(pallas::Base::from(self.yes_votes_value))),
  124. Witness::Base(Value::known(pallas::Base::from(self.all_votes_value))),
  125. Witness::Scalar(Value::known(self.yes_votes_blind)),
  126. Witness::Scalar(Value::known(self.all_votes_blind)),
  127. // outputs + inputs
  128. Witness::Base(Value::known(self.user_serial)),
  129. Witness::Base(Value::known(self.user_coin_blind)),
  130. Witness::Base(Value::known(self.dao_serial)),
  131. Witness::Base(Value::known(self.dao_coin_blind)),
  132. Witness::Base(Value::known(input_value)),
  133. Witness::Scalar(Value::known(self.input_value_blind)),
  134. // misc
  135. Witness::Base(Value::known(self.hook_dao_exec)),
  136. Witness::Base(Value::known(user_spend_hook)),
  137. Witness::Base(Value::known(user_data)),
  138. ];
  139. let public_inputs = vec![
  140. proposal_bulla,
  141. coin_0,
  142. coin_1,
  143. *yes_votes_commit_coords.x(),
  144. *yes_votes_commit_coords.y(),
  145. *all_votes_commit_coords.x(),
  146. *all_votes_commit_coords.y(),
  147. *input_value_commit_coords.x(),
  148. *input_value_commit_coords.y(),
  149. self.hook_dao_exec,
  150. user_spend_hook,
  151. user_data,
  152. ];
  153. let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
  154. debug!(target: "example_contract::foo::wallet::Builder", "input_proof Proof::create()");
  155. let proving_key = &zk_info.proving_key;
  156. let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
  157. .expect("DAO::exec() proving error!)");
  158. proofs.push(input_proof);
  159. let call_data = CallData {
  160. proposal: proposal_bulla,
  161. coin_0,
  162. coin_1,
  163. yes_votes_commit,
  164. all_votes_commit,
  165. input_value_commit,
  166. };
  167. FuncCall {
  168. contract_id: *CONTRACT_ID,
  169. func_id: *super::FUNC_ID,
  170. call_data: Box::new(call_data),
  171. proofs,
  172. }
  173. }
  174. }