wallet.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use darkfi_sdk::crypto::MerkleNode;
  19. use darkfi_serial::{SerialDecodable, SerialEncodable};
  20. use halo2_proofs::circuit::Value;
  21. use incrementalmerkletree::Hashable;
  22. use pasta_curves::{
  23. arithmetic::CurveAffine,
  24. group::{ff::Field, Curve},
  25. pallas,
  26. };
  27. use rand::rngs::OsRng;
  28. use darkfi::{
  29. crypto::{
  30. keypair::{PublicKey, SecretKey},
  31. util::{pedersen_commitment_u64, poseidon_hash},
  32. Proof,
  33. },
  34. zk::vm::{Witness, ZkCircuit},
  35. };
  36. use crate::{
  37. contract::{
  38. dao::{
  39. mint::wallet::DaoParams,
  40. propose::validate::{CallData, Header, Input},
  41. CONTRACT_ID,
  42. },
  43. money,
  44. },
  45. note,
  46. util::{FuncCall, ZkContractInfo, ZkContractTable},
  47. };
  48. #[derive(SerialEncodable, SerialDecodable)]
  49. pub struct Note {
  50. pub proposal: Proposal,
  51. }
  52. pub struct BuilderInput {
  53. pub secret: SecretKey,
  54. pub note: money::transfer::wallet::Note,
  55. pub leaf_position: incrementalmerkletree::Position,
  56. pub merkle_path: Vec<MerkleNode>,
  57. pub signature_secret: SecretKey,
  58. }
  59. #[derive(SerialEncodable, SerialDecodable, Clone)]
  60. pub struct Proposal {
  61. pub dest: PublicKey,
  62. pub amount: u64,
  63. pub serial: pallas::Base,
  64. pub token_id: pallas::Base,
  65. pub blind: pallas::Base,
  66. }
  67. pub struct Builder {
  68. pub inputs: Vec<BuilderInput>,
  69. pub proposal: Proposal,
  70. pub dao: DaoParams,
  71. pub dao_leaf_position: incrementalmerkletree::Position,
  72. pub dao_merkle_path: Vec<MerkleNode>,
  73. pub dao_merkle_root: MerkleNode,
  74. }
  75. impl Builder {
  76. pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall {
  77. let mut proofs = vec![];
  78. let gov_token_blind = pallas::Base::random(&mut OsRng);
  79. let mut inputs = vec![];
  80. let mut total_funds = 0;
  81. let mut total_funds_blinds = pallas::Scalar::from(0);
  82. for input in self.inputs {
  83. let funds_blind = pallas::Scalar::random(&mut OsRng);
  84. total_funds += input.note.value;
  85. total_funds_blinds += funds_blind;
  86. let signature_public = PublicKey::from_secret(input.signature_secret);
  87. let zk_info = zk_bins.lookup(&"dao-propose-burn".to_string()).unwrap();
  88. let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
  89. info
  90. } else {
  91. panic!("Not binary info")
  92. };
  93. let zk_bin = zk_info.bincode.clone();
  94. // Note from the previous output
  95. let note = input.note;
  96. let leaf_pos: u64 = input.leaf_position.into();
  97. let prover_witnesses = vec![
  98. Witness::Base(Value::known(input.secret.0)),
  99. Witness::Base(Value::known(note.serial)),
  100. Witness::Base(Value::known(pallas::Base::from(0))),
  101. Witness::Base(Value::known(pallas::Base::from(0))),
  102. Witness::Base(Value::known(pallas::Base::from(note.value))),
  103. Witness::Base(Value::known(note.token_id)),
  104. Witness::Base(Value::known(note.coin_blind)),
  105. Witness::Scalar(Value::known(funds_blind)),
  106. Witness::Base(Value::known(gov_token_blind)),
  107. Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
  108. Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
  109. Witness::Base(Value::known(input.signature_secret.0)),
  110. ];
  111. let public_key = PublicKey::from_secret(input.secret);
  112. let coords = public_key.0.to_affine().coordinates().unwrap();
  113. let coin = poseidon_hash::<8>([
  114. *coords.x(),
  115. *coords.y(),
  116. pallas::Base::from(note.value),
  117. note.token_id,
  118. note.serial,
  119. pallas::Base::from(0),
  120. pallas::Base::from(0),
  121. note.coin_blind,
  122. ]);
  123. let merkle_root = {
  124. let position: u64 = input.leaf_position.into();
  125. let mut current = MerkleNode::from(coin);
  126. for (level, sibling) in input.merkle_path.iter().enumerate() {
  127. let level = level as u8;
  128. current = if position & (1 << level) == 0 {
  129. MerkleNode::combine(level.into(), &current, sibling)
  130. } else {
  131. MerkleNode::combine(level.into(), sibling, &current)
  132. };
  133. }
  134. current
  135. };
  136. let token_commit = poseidon_hash::<2>([note.token_id, gov_token_blind]);
  137. assert_eq!(self.dao.gov_token_id, note.token_id);
  138. let value_commit = pedersen_commitment_u64(note.value, funds_blind);
  139. let value_coords = value_commit.to_affine().coordinates().unwrap();
  140. let sigpub_coords = signature_public.0.to_affine().coordinates().unwrap();
  141. let public_inputs = vec![
  142. *value_coords.x(),
  143. *value_coords.y(),
  144. token_commit,
  145. merkle_root.inner(),
  146. *sigpub_coords.x(),
  147. *sigpub_coords.y(),
  148. ];
  149. let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
  150. let proving_key = &zk_info.proving_key;
  151. let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
  152. .expect("DAO::propose() proving error!");
  153. proofs.push(input_proof);
  154. let input = Input { value_commit, merkle_root, signature_public };
  155. inputs.push(input);
  156. }
  157. let total_funds_commit = pedersen_commitment_u64(total_funds, total_funds_blinds);
  158. let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
  159. let total_funds = pallas::Base::from(total_funds);
  160. let token_commit = poseidon_hash::<2>([self.dao.gov_token_id, gov_token_blind]);
  161. let proposal_dest_coords = self.proposal.dest.0.to_affine().coordinates().unwrap();
  162. let proposal_dest_x = *proposal_dest_coords.x();
  163. let proposal_dest_y = *proposal_dest_coords.y();
  164. let proposal_amount = pallas::Base::from(self.proposal.amount);
  165. let dao_proposer_limit = pallas::Base::from(self.dao.proposer_limit);
  166. let dao_quorum = pallas::Base::from(self.dao.quorum);
  167. let dao_approval_ratio_quot = pallas::Base::from(self.dao.approval_ratio_quot);
  168. let dao_approval_ratio_base = pallas::Base::from(self.dao.approval_ratio_base);
  169. let dao_pubkey_coords = self.dao.public_key.0.to_affine().coordinates().unwrap();
  170. let dao_bulla = poseidon_hash::<8>([
  171. dao_proposer_limit,
  172. dao_quorum,
  173. dao_approval_ratio_quot,
  174. dao_approval_ratio_base,
  175. self.dao.gov_token_id,
  176. *dao_pubkey_coords.x(),
  177. *dao_pubkey_coords.y(),
  178. self.dao.bulla_blind,
  179. ]);
  180. let dao_leaf_position: u64 = self.dao_leaf_position.into();
  181. let proposal_bulla = poseidon_hash::<8>([
  182. proposal_dest_x,
  183. proposal_dest_y,
  184. proposal_amount,
  185. self.proposal.serial,
  186. self.proposal.token_id,
  187. dao_bulla,
  188. self.proposal.blind,
  189. // @tmp-workaround
  190. self.proposal.blind,
  191. ]);
  192. let zk_info = zk_bins.lookup(&"dao-propose-main".to_string()).unwrap();
  193. let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
  194. info
  195. } else {
  196. panic!("Not binary info")
  197. };
  198. let zk_bin = zk_info.bincode.clone();
  199. let prover_witnesses = vec![
  200. // Proposers total number of gov tokens
  201. Witness::Base(Value::known(total_funds)),
  202. Witness::Scalar(Value::known(total_funds_blinds)),
  203. // Used for blinding exported gov token ID
  204. Witness::Base(Value::known(gov_token_blind)),
  205. // proposal params
  206. Witness::Base(Value::known(proposal_dest_x)),
  207. Witness::Base(Value::known(proposal_dest_y)),
  208. Witness::Base(Value::known(proposal_amount)),
  209. Witness::Base(Value::known(self.proposal.serial)),
  210. Witness::Base(Value::known(self.proposal.token_id)),
  211. Witness::Base(Value::known(self.proposal.blind)),
  212. // DAO params
  213. Witness::Base(Value::known(dao_proposer_limit)),
  214. Witness::Base(Value::known(dao_quorum)),
  215. Witness::Base(Value::known(dao_approval_ratio_quot)),
  216. Witness::Base(Value::known(dao_approval_ratio_base)),
  217. Witness::Base(Value::known(self.dao.gov_token_id)),
  218. Witness::Base(Value::known(*dao_pubkey_coords.x())),
  219. Witness::Base(Value::known(*dao_pubkey_coords.y())),
  220. Witness::Base(Value::known(self.dao.bulla_blind)),
  221. Witness::Uint32(Value::known(dao_leaf_position.try_into().unwrap())),
  222. Witness::MerklePath(Value::known(self.dao_merkle_path.try_into().unwrap())),
  223. ];
  224. let public_inputs = vec![
  225. token_commit,
  226. self.dao_merkle_root.inner(),
  227. proposal_bulla,
  228. *total_funds_coords.x(),
  229. *total_funds_coords.y(),
  230. ];
  231. let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
  232. let proving_key = &zk_info.proving_key;
  233. let main_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
  234. .expect("DAO::propose() proving error!");
  235. proofs.push(main_proof);
  236. let note = Note { proposal: self.proposal };
  237. let enc_note = note::encrypt(&note, &self.dao.public_key).unwrap();
  238. let header = Header {
  239. dao_merkle_root: self.dao_merkle_root,
  240. proposal_bulla,
  241. token_commit,
  242. enc_note,
  243. };
  244. let call_data = CallData { header, inputs };
  245. FuncCall {
  246. contract_id: *CONTRACT_ID,
  247. func_id: *super::FUNC_ID,
  248. call_data: Box::new(call_data),
  249. proofs,
  250. }
  251. }
  252. }