rpc_swap.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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 anyhow::{anyhow, Result};
  19. use darkfi::{
  20. tx::Transaction,
  21. zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses, Proof},
  22. zkas::ZkBinary,
  23. };
  24. use darkfi_money_contract::{
  25. client::{build_half_swap_tx, EncryptedNote},
  26. state::MoneyTransferParams,
  27. MoneyFunction, ZKAS_BURN_NS, ZKAS_MINT_NS,
  28. };
  29. use darkfi_sdk::{
  30. crypto::{pedersen::ValueBlind, ContractId, SecretKey, TokenId},
  31. pasta::pallas,
  32. tx::ContractCall,
  33. };
  34. use darkfi_serial::{deserialize, Encodable, SerialDecodable, SerialEncodable};
  35. use rand::rngs::OsRng;
  36. use super::Drk;
  37. #[derive(SerialEncodable, SerialDecodable)]
  38. /// Half of the swap data, includes the coin that is supposed to be sent,
  39. /// and the coin that is supposed to be received.
  40. pub struct PartialSwapData {
  41. params: MoneyTransferParams,
  42. proofs: Vec<Proof>,
  43. value_pair: (u64, u64),
  44. token_pair: (TokenId, TokenId),
  45. value_blinds: Vec<ValueBlind>,
  46. token_blinds: Vec<ValueBlind>,
  47. }
  48. impl Drk {
  49. /// Initialize the first half of an atomic swap
  50. pub async fn init_swap(
  51. &self,
  52. value_send: u64,
  53. token_send: TokenId,
  54. value_recv: u64,
  55. token_recv: TokenId,
  56. ) -> Result<PartialSwapData> {
  57. // First we'll fetch all of our unspent coins from the wallet.
  58. let mut owncoins = self.wallet_coins(false).await?;
  59. // Then we see if we have one that we can send.
  60. owncoins.retain(|x| (x.0.note.value == value_send && x.0.note.token_id == token_send));
  61. if owncoins.is_empty() {
  62. return Err(anyhow!(
  63. "Did not find any unspent coins of value {} and token_id {}",
  64. value_send,
  65. token_send
  66. ))
  67. }
  68. // If there are any, we'll just spend the first one we see.
  69. let burn_coin = owncoins[0].0.clone();
  70. // Fetch our default address
  71. let address = self.wallet_address(0).await?;
  72. // We'll also need our Merkle tree
  73. let tree = self.wallet_tree().await?;
  74. // TODO: FIXME: Do not hardcode the contract ID
  75. let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
  76. // Now we need to do a lookup for the zkas proof bincodes, and create
  77. // the circuit objects and proving keys so we can build the transaction.
  78. // We also do this through the RPC.
  79. let zkas_bins = self.lookup_zkas(&contract_id).await?;
  80. let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == ZKAS_MINT_NS) else {
  81. return Err(anyhow!("Mint circuit not found"))
  82. };
  83. let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == ZKAS_BURN_NS) else {
  84. return Err(anyhow!("Burn circuit not found"))
  85. };
  86. let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
  87. let burn_zkbin = ZkBinary::decode(&burn_zkbin.1)?;
  88. let k = 13;
  89. let mint_circuit = ZkCircuit::new(empty_witnesses(&mint_zkbin), mint_zkbin.clone());
  90. let burn_circuit = ZkCircuit::new(empty_witnesses(&burn_zkbin), burn_zkbin.clone());
  91. eprintln!("Creating Mint circuit proving key");
  92. let mint_pk = ProvingKey::build(k, &mint_circuit);
  93. eprintln!("Creating Burn circuit proving key");
  94. let burn_pk = ProvingKey::build(k, &burn_circuit);
  95. // Now we should have everything we need to build the swap half
  96. eprintln!("Building first half of the swap transaction");
  97. let (half_params, half_proofs, _half_keys, _spent_coins, value_blinds, token_blinds) =
  98. build_half_swap_tx(
  99. &address,
  100. value_send,
  101. token_send,
  102. value_recv,
  103. token_recv,
  104. &[],
  105. &[],
  106. &[burn_coin],
  107. &tree,
  108. &mint_zkbin,
  109. &mint_pk,
  110. &burn_zkbin,
  111. &burn_pk,
  112. )?;
  113. // Now we have the half, so we can build `PartialSwapData` and return it.
  114. let ret = PartialSwapData {
  115. params: half_params,
  116. proofs: half_proofs,
  117. value_pair: (value_send, value_recv),
  118. token_pair: (token_send, token_recv),
  119. value_blinds,
  120. token_blinds,
  121. };
  122. Ok(ret)
  123. }
  124. /// Create a full transaction by inspecting and verifying given partial swap data,
  125. /// making the other half, and joining all this into a `Transaction` object.
  126. pub async fn join_swap(&self, partial: PartialSwapData) -> Result<Transaction> {
  127. // Our side of the tx in the pairs is the second half, so we try to find
  128. // an unspent coin like that in our wallet.
  129. let mut owncoins = self.wallet_coins(false).await?;
  130. owncoins.retain(|x| {
  131. x.0.note.value == partial.value_pair.1 && x.0.note.token_id == partial.token_pair.1
  132. });
  133. if owncoins.is_empty() {
  134. return Err(anyhow!(
  135. "Did not find any unspent coins of value {} and token_id {}",
  136. partial.value_pair.1,
  137. partial.token_pair.1
  138. ))
  139. }
  140. // If there are any, we'll just spend the first one we see.
  141. let burn_coin = owncoins[0].0.clone();
  142. // Fetch our default address
  143. let address = self.wallet_address(0).await?;
  144. // We'll also need our Merkle tree
  145. let tree = self.wallet_tree().await?;
  146. // TODO: FIXME: Do not hardcode the contract ID
  147. let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
  148. // Now we need to do a lookup for the zkas proof bincodes, and create
  149. // the circuit objects and proving keys so we can build the transaction.
  150. // We also do this through the RPC.
  151. let zkas_bins = self.lookup_zkas(&contract_id).await?;
  152. let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == ZKAS_MINT_NS) else {
  153. return Err(anyhow!("Mint circuit not found"))
  154. };
  155. let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == ZKAS_BURN_NS) else {
  156. return Err(anyhow!("Burn circuit not found"))
  157. };
  158. let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
  159. let burn_zkbin = ZkBinary::decode(&burn_zkbin.1)?;
  160. let k = 13;
  161. let mint_circuit = ZkCircuit::new(empty_witnesses(&mint_zkbin), mint_zkbin.clone());
  162. let burn_circuit = ZkCircuit::new(empty_witnesses(&burn_zkbin), burn_zkbin.clone());
  163. eprintln!("Creating Mint circuit proving key");
  164. let mint_pk = ProvingKey::build(k, &mint_circuit);
  165. eprintln!("Creating Burn circuit proving key");
  166. let burn_pk = ProvingKey::build(k, &burn_circuit);
  167. // TODO: Maybe some kind of verification at this point
  168. // Now we should have everything we need to build the swap half
  169. eprintln!("Building second half of the swap transaction");
  170. let (half_params, half_proofs, half_keys, _spent_coins, _value_blinds, _token_blinds) =
  171. build_half_swap_tx(
  172. &address,
  173. partial.value_pair.1,
  174. partial.token_pair.1,
  175. partial.value_pair.0,
  176. partial.token_pair.0,
  177. &partial.value_blinds,
  178. &partial.token_blinds,
  179. &[burn_coin],
  180. &tree,
  181. &mint_zkbin,
  182. &mint_pk,
  183. &burn_zkbin,
  184. &burn_pk,
  185. )?;
  186. let full_params = MoneyTransferParams {
  187. clear_inputs: vec![],
  188. inputs: vec![partial.params.inputs[0].clone(), half_params.inputs[0].clone()],
  189. outputs: vec![partial.params.outputs[0].clone(), half_params.outputs[0].clone()],
  190. };
  191. let full_proofs = vec![
  192. partial.proofs[0].clone(),
  193. half_proofs[0].clone(),
  194. partial.proofs[1].clone(),
  195. half_proofs[1].clone(),
  196. ];
  197. let mut data = vec![MoneyFunction::OtcSwap as u8];
  198. full_params.encode(&mut data)?;
  199. let mut tx = Transaction {
  200. calls: vec![ContractCall { contract_id, data }],
  201. proofs: vec![full_proofs],
  202. signatures: vec![],
  203. };
  204. eprintln!("Signing swap transaction");
  205. let sigs = tx.create_sigs(&mut OsRng, &half_keys)?;
  206. tx.signatures = vec![sigs];
  207. Ok(tx)
  208. }
  209. /// Sign a given transaction by retrieving the secret key from the encrypted
  210. /// note and prepending it to the transaction's signatures.
  211. pub async fn sign_swap(&self, tx: &mut Transaction) -> Result<()> {
  212. // We need our secret keys to try and decrypt the note
  213. let secret_keys = self.wallet_secrets().await?;
  214. let params: MoneyTransferParams = deserialize(&tx.calls[0].data[1..])?;
  215. // Our output should be outputs[0] so we try to decrypt that.
  216. let ciphertext = params.outputs[0].ciphertext.clone();
  217. let ephem_public = params.outputs[0].ephem_public;
  218. let encrypted_note = EncryptedNote { ciphertext, ephem_public };
  219. eprintln!("Trying to decrypt note in outputs[0]");
  220. let mut skey = None;
  221. for secret in &secret_keys {
  222. if let Ok(note) = encrypted_note.decrypt(secret) {
  223. let s: SecretKey = deserialize(&note.memo)?;
  224. eprintln!("Successfully decrypted and found an ephemeral secret");
  225. skey = Some(s);
  226. break
  227. }
  228. }
  229. let Some(skey) = skey else {
  230. eprintln!("Error: Failed to decrypt note with any of our secret keys");
  231. return Err(anyhow!("Failed to decrypt note with any of our secret keys"))
  232. };
  233. eprintln!("Signing swap transaction");
  234. let sigs = tx.create_sigs(&mut OsRng, &[skey])?;
  235. tx.signatures[0].insert(0, sigs[0]);
  236. Ok(())
  237. }
  238. }