wallet.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. use darkfi::{
  2. crypto::{
  3. keypair::{Keypair, PublicKey, SecretKey},
  4. merkle_node::MerkleNode,
  5. nullifier::Nullifier,
  6. util::{pedersen_commitment_u64, poseidon_hash},
  7. Proof,
  8. },
  9. util::serial::{SerialDecodable, SerialEncodable},
  10. zk::vm::{Witness, ZkCircuit},
  11. };
  12. use halo2_proofs::circuit::Value;
  13. use incrementalmerkletree::Hashable;
  14. use pasta_curves::{
  15. arithmetic::CurveAffine,
  16. group::{ff::Field, Curve},
  17. pallas,
  18. };
  19. use rand::rngs::OsRng;
  20. use crate::{
  21. dao_contract::{
  22. mint::wallet::DaoParams,
  23. propose::wallet::Proposal,
  24. vote::validate::{CallData, Header, Input},
  25. },
  26. demo::{FuncCall, ZkContractInfo, ZkContractTable},
  27. money_contract, note,
  28. };
  29. use log::debug;
  30. #[derive(SerialEncodable, SerialDecodable)]
  31. pub struct Note {
  32. pub vote: Vote,
  33. pub value: u64,
  34. pub value_blind: pallas::Scalar,
  35. }
  36. #[derive(SerialEncodable, SerialDecodable)]
  37. // All info needed for vote and value commits
  38. pub struct Vote {
  39. pub vote_option: bool,
  40. pub vote_option_blind: pallas::Scalar,
  41. }
  42. pub struct BuilderInput {
  43. pub secret: SecretKey,
  44. pub note: money_contract::transfer::wallet::Note,
  45. pub leaf_position: incrementalmerkletree::Position,
  46. pub merkle_path: Vec<MerkleNode>,
  47. pub signature_secret: SecretKey,
  48. }
  49. // TODO: should be token locking voting?
  50. // Inside ZKproof, check proposal is correct.
  51. pub struct Builder {
  52. pub inputs: Vec<BuilderInput>,
  53. pub vote: Vote,
  54. pub vote_keypair: Keypair,
  55. pub proposal: Proposal,
  56. pub dao: DaoParams,
  57. }
  58. impl Builder {
  59. pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall {
  60. debug!(target: "dao_contract::vote::wallet::Builder", "build()");
  61. let mut proofs = vec![];
  62. let gov_token_blind = pallas::Base::random(&mut OsRng);
  63. let mut inputs = vec![];
  64. let mut value = 0;
  65. let mut value_blind = pallas::Scalar::from(0);
  66. for input in self.inputs {
  67. let input_value_blind = pallas::Scalar::random(&mut OsRng);
  68. value += input.note.value;
  69. value_blind += input_value_blind;
  70. let signature_public = PublicKey::from_secret(input.signature_secret);
  71. let zk_info = zk_bins.lookup(&"dao-vote-burn".to_string()).unwrap();
  72. let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
  73. info
  74. } else {
  75. panic!("Not binary info")
  76. };
  77. let zk_bin = zk_info.bincode.clone();
  78. // Note from the previous output
  79. let note = input.note;
  80. let leaf_pos: u64 = input.leaf_position.into();
  81. let prover_witnesses = vec![
  82. Witness::Base(Value::known(input.secret.0)),
  83. Witness::Base(Value::known(note.serial)),
  84. Witness::Base(Value::known(pallas::Base::from(0))),
  85. Witness::Base(Value::known(pallas::Base::from(0))),
  86. Witness::Base(Value::known(pallas::Base::from(note.value))),
  87. Witness::Base(Value::known(note.token_id)),
  88. Witness::Base(Value::known(note.coin_blind)),
  89. Witness::Scalar(Value::known(input_value_blind)),
  90. Witness::Base(Value::known(gov_token_blind)),
  91. Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
  92. Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
  93. Witness::Base(Value::known(input.signature_secret.0)),
  94. ];
  95. let public_key = PublicKey::from_secret(input.secret);
  96. let coords = public_key.0.to_affine().coordinates().unwrap();
  97. let coin = poseidon_hash::<8>([
  98. *coords.x(),
  99. *coords.y(),
  100. pallas::Base::from(note.value),
  101. note.token_id,
  102. note.serial,
  103. pallas::Base::from(0),
  104. pallas::Base::from(0),
  105. note.coin_blind,
  106. ]);
  107. let merkle_root = {
  108. let position: u64 = input.leaf_position.into();
  109. let mut current = MerkleNode(coin);
  110. for (level, sibling) in input.merkle_path.iter().enumerate() {
  111. let level = level as u8;
  112. current = if position & (1 << level) == 0 {
  113. MerkleNode::combine(level.into(), &current, sibling)
  114. } else {
  115. MerkleNode::combine(level.into(), sibling, &current)
  116. };
  117. }
  118. current
  119. };
  120. let token_commit = poseidon_hash::<2>([note.token_id, gov_token_blind]);
  121. assert_eq!(self.dao.gov_token_id, note.token_id);
  122. let nullifier = poseidon_hash::<2>([input.secret.0, note.serial]);
  123. let value_commit = pedersen_commitment_u64(note.value, value_blind);
  124. let value_coords = value_commit.to_affine().coordinates().unwrap();
  125. let value_commit_x = *value_coords.x();
  126. let value_commit_y = *value_coords.y();
  127. let sigpub_coords = signature_public.0.to_affine().coordinates().unwrap();
  128. let sigpub_x = *sigpub_coords.x();
  129. let sigpub_y = *sigpub_coords.y();
  130. let public_inputs = vec![
  131. nullifier,
  132. value_commit_x,
  133. value_commit_y,
  134. token_commit,
  135. merkle_root.0,
  136. sigpub_x,
  137. sigpub_y,
  138. ];
  139. let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
  140. let proving_key = &zk_info.proving_key;
  141. debug!(target: "dao_contract::vote::wallet::Builder", "input_proof Proof::create()");
  142. let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
  143. .expect("DAO::vote() proving error!");
  144. proofs.push(input_proof);
  145. let input = Input {
  146. nullifier: Nullifier(nullifier),
  147. value_commit,
  148. merkle_root,
  149. signature_public,
  150. };
  151. inputs.push(input);
  152. }
  153. let token_commit = poseidon_hash::<2>([self.dao.gov_token_id, gov_token_blind]);
  154. let proposal_dest_coords = self.proposal.dest.0.to_affine().coordinates().unwrap();
  155. let proposal_amount = pallas::Base::from(self.proposal.amount);
  156. let dao_proposer_limit = pallas::Base::from(self.dao.proposer_limit);
  157. let dao_quorum = pallas::Base::from(self.dao.quorum);
  158. let dao_approval_ratio = pallas::Base::from(self.dao.approval_ratio);
  159. let dao_pubkey_coords = self.dao.public_key.0.to_affine().coordinates().unwrap();
  160. let dao_bulla = poseidon_hash::<8>([
  161. dao_proposer_limit,
  162. dao_quorum,
  163. dao_approval_ratio,
  164. self.dao.gov_token_id,
  165. *dao_pubkey_coords.x(),
  166. *dao_pubkey_coords.y(),
  167. self.dao.bulla_blind,
  168. // @tmp-workaround
  169. self.dao.bulla_blind,
  170. ]);
  171. let proposal_bulla = poseidon_hash::<8>([
  172. *proposal_dest_coords.x(),
  173. *proposal_dest_coords.y(),
  174. //proposal_dest_x,
  175. //proposal_dest_y,
  176. proposal_amount,
  177. self.proposal.serial,
  178. self.proposal.token_id,
  179. dao_bulla,
  180. self.proposal.blind,
  181. // @tmp-workaround
  182. self.proposal.blind,
  183. ]);
  184. let vote = self.vote.vote_option as u64;
  185. assert!(vote == 0 || vote == 1);
  186. let weighted_vote = vote * value;
  187. let vote_commit = pedersen_commitment_u64(weighted_vote, self.vote.vote_option_blind);
  188. debug!(target: "demo::dao_contract::vote::wallet::Builder", "vote commit: {:?}", vote_commit);
  189. let vote_coords = vote_commit.to_affine().coordinates().unwrap();
  190. let vote = pallas::Base::from(vote);
  191. let value_commit = pedersen_commitment_u64(value, value_blind);
  192. let value_coords = value_commit.to_affine().coordinates().unwrap();
  193. let value_base = pallas::Base::from(value);
  194. let zk_info = zk_bins.lookup(&"dao-vote-main".to_string()).unwrap();
  195. let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
  196. info
  197. } else {
  198. panic!("Not binary info")
  199. };
  200. let zk_bin = zk_info.bincode.clone();
  201. let prover_witnesses = vec![
  202. // proposal params
  203. Witness::Base(Value::known(*proposal_dest_coords.x())),
  204. Witness::Base(Value::known(*proposal_dest_coords.y())),
  205. Witness::Base(Value::known(proposal_amount)),
  206. Witness::Base(Value::known(self.proposal.serial)),
  207. Witness::Base(Value::known(self.proposal.token_id)),
  208. Witness::Base(Value::known(self.proposal.blind)),
  209. // DAO params
  210. Witness::Base(Value::known(dao_proposer_limit)),
  211. Witness::Base(Value::known(dao_quorum)),
  212. Witness::Base(Value::known(dao_approval_ratio)),
  213. Witness::Base(Value::known(self.dao.gov_token_id)),
  214. Witness::Base(Value::known(*dao_pubkey_coords.x())),
  215. Witness::Base(Value::known(*dao_pubkey_coords.y())),
  216. Witness::Base(Value::known(self.dao.bulla_blind)),
  217. // Vote
  218. Witness::Base(Value::known(vote)),
  219. Witness::Scalar(Value::known(self.vote.vote_option_blind)),
  220. // Total number of gov tokens allocated
  221. Witness::Base(Value::known(value_base)),
  222. Witness::Scalar(Value::known(value_blind)),
  223. // gov token
  224. Witness::Base(Value::known(gov_token_blind)),
  225. ];
  226. let public_inputs = vec![
  227. token_commit,
  228. proposal_bulla,
  229. *vote_coords.x(),
  230. *vote_coords.y(),
  231. *value_coords.x(),
  232. *value_coords.y(),
  233. ];
  234. let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
  235. let proving_key = &zk_info.proving_key;
  236. debug!(target: "dao_contract::vote::wallet::Builder", "main_proof = Proof::create()");
  237. let main_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
  238. .expect("DAO::vote() proving error!");
  239. proofs.push(main_proof);
  240. let note = Note { vote: self.vote, value, value_blind };
  241. let enc_note = note::encrypt(&note, &self.vote_keypair.public).unwrap();
  242. let header = Header { token_commit, proposal_bulla, vote_commit, enc_note };
  243. let call_data = CallData { header, inputs };
  244. FuncCall {
  245. contract_id: "DAO".to_string(),
  246. func_id: "DAO::vote()".to_string(),
  247. call_data: Box::new(call_data),
  248. proofs,
  249. }
  250. }
  251. }