wallet.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. use darkfi_serial::{SerialDecodable, SerialEncodable};
  2. use pasta_curves::group::ff::Field;
  3. use rand::rngs::OsRng;
  4. use darkfi::{
  5. crypto::{
  6. burn_proof::create_burn_proof,
  7. keypair::{PublicKey, SecretKey},
  8. merkle_node::MerkleNode,
  9. mint_proof::create_mint_proof,
  10. types::{
  11. DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData, DrkUserDataBlind,
  12. DrkValueBlind,
  13. },
  14. },
  15. Result,
  16. };
  17. use crate::{
  18. contract::money_contract::{
  19. transfer::validate::{CallData, ClearInput, Input, Output},
  20. CONTRACT_ID,
  21. },
  22. note,
  23. util::{FuncCall, ZkContractInfo, ZkContractTable},
  24. };
  25. #[derive(Clone, SerialEncodable, SerialDecodable)]
  26. pub struct Note {
  27. pub serial: DrkSerial,
  28. pub value: u64,
  29. pub token_id: DrkTokenId,
  30. pub spend_hook: DrkSpendHook,
  31. pub user_data: DrkUserData,
  32. pub coin_blind: DrkCoinBlind,
  33. pub value_blind: DrkValueBlind,
  34. pub token_blind: DrkValueBlind,
  35. }
  36. pub struct Builder {
  37. pub clear_inputs: Vec<BuilderClearInputInfo>,
  38. pub inputs: Vec<BuilderInputInfo>,
  39. pub outputs: Vec<BuilderOutputInfo>,
  40. }
  41. pub struct BuilderClearInputInfo {
  42. pub value: u64,
  43. pub token_id: DrkTokenId,
  44. pub signature_secret: SecretKey,
  45. }
  46. pub struct BuilderInputInfo {
  47. pub leaf_position: incrementalmerkletree::Position,
  48. pub merkle_path: Vec<MerkleNode>,
  49. pub secret: SecretKey,
  50. pub note: Note,
  51. pub user_data_blind: DrkUserDataBlind,
  52. pub value_blind: DrkValueBlind,
  53. pub signature_secret: SecretKey,
  54. }
  55. pub struct BuilderOutputInfo {
  56. pub value: u64,
  57. pub token_id: DrkTokenId,
  58. pub public: PublicKey,
  59. pub serial: DrkSerial,
  60. pub coin_blind: DrkCoinBlind,
  61. pub spend_hook: DrkSpendHook,
  62. pub user_data: DrkUserData,
  63. }
  64. impl Builder {
  65. fn compute_remainder_blind(
  66. clear_inputs: &[ClearInput],
  67. input_blinds: &[DrkValueBlind],
  68. output_blinds: &[DrkValueBlind],
  69. ) -> DrkValueBlind {
  70. let mut total = DrkValueBlind::zero();
  71. for input in clear_inputs {
  72. total += input.value_blind;
  73. }
  74. for input_blind in input_blinds {
  75. total += input_blind;
  76. }
  77. for output_blind in output_blinds {
  78. total -= output_blind;
  79. }
  80. total
  81. }
  82. pub fn build(self, zk_bins: &ZkContractTable) -> Result<FuncCall> {
  83. assert!(self.clear_inputs.len() + self.inputs.len() > 0);
  84. let mut clear_inputs = vec![];
  85. let token_blind = DrkValueBlind::random(&mut OsRng);
  86. for input in &self.clear_inputs {
  87. let signature_public = PublicKey::from_secret(input.signature_secret);
  88. let value_blind = DrkValueBlind::random(&mut OsRng);
  89. let clear_input = ClearInput {
  90. value: input.value,
  91. token_id: input.token_id,
  92. value_blind,
  93. token_blind,
  94. signature_public,
  95. };
  96. clear_inputs.push(clear_input);
  97. }
  98. let mut proofs = vec![];
  99. let mut inputs = vec![];
  100. let mut input_blinds = vec![];
  101. for input in self.inputs {
  102. let value_blind = input.value_blind;
  103. input_blinds.push(value_blind);
  104. let zk_info = zk_bins.lookup(&"money-transfer-burn".to_string()).unwrap();
  105. let zk_info = if let ZkContractInfo::Native(info) = zk_info {
  106. info
  107. } else {
  108. panic!("Not native info")
  109. };
  110. let burn_pk = &zk_info.proving_key;
  111. // Note from the previous output
  112. let note = input.note.clone();
  113. let (burn_proof, revealed) = create_burn_proof(
  114. burn_pk,
  115. note.value,
  116. note.token_id,
  117. value_blind,
  118. token_blind,
  119. note.serial,
  120. note.spend_hook,
  121. note.user_data,
  122. input.user_data_blind,
  123. note.coin_blind,
  124. input.secret,
  125. input.leaf_position,
  126. input.merkle_path.clone(),
  127. input.signature_secret,
  128. )?;
  129. proofs.push(burn_proof);
  130. let input = Input { revealed };
  131. inputs.push(input);
  132. }
  133. let mut outputs = vec![];
  134. let mut output_blinds = vec![];
  135. // This value_blind calc assumes there will always be at least a single output
  136. assert!(!self.outputs.is_empty());
  137. for (i, output) in self.outputs.iter().enumerate() {
  138. let value_blind = if i == self.outputs.len() - 1 {
  139. Self::compute_remainder_blind(&clear_inputs, &input_blinds, &output_blinds)
  140. } else {
  141. DrkValueBlind::random(&mut OsRng)
  142. };
  143. output_blinds.push(value_blind);
  144. let serial = output.serial;
  145. let coin_blind = output.coin_blind;
  146. let zk_info = zk_bins.lookup(&"money-transfer-mint".to_string()).unwrap();
  147. let zk_info = if let ZkContractInfo::Native(info) = zk_info {
  148. info
  149. } else {
  150. panic!("Not native info")
  151. };
  152. let mint_pk = &zk_info.proving_key;
  153. let (mint_proof, revealed) = create_mint_proof(
  154. mint_pk,
  155. output.value,
  156. output.token_id,
  157. value_blind,
  158. token_blind,
  159. serial,
  160. output.spend_hook,
  161. output.user_data,
  162. coin_blind,
  163. output.public,
  164. )?;
  165. proofs.push(mint_proof);
  166. let note = Note {
  167. serial,
  168. value: output.value,
  169. token_id: output.token_id,
  170. spend_hook: output.spend_hook,
  171. user_data: output.user_data,
  172. coin_blind,
  173. value_blind,
  174. token_blind,
  175. };
  176. let encrypted_note = note::encrypt(&note, &output.public)?;
  177. let output = Output { revealed, enc_note: encrypted_note };
  178. outputs.push(output);
  179. }
  180. let call_data = CallData { clear_inputs, inputs, outputs };
  181. Ok(FuncCall {
  182. contract_id: *CONTRACT_ID,
  183. func_id: *super::FUNC_ID,
  184. call_data: Box::new(call_data),
  185. proofs,
  186. })
  187. }
  188. }