rpc_swap.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 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. util::parse::encode_base10,
  22. zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses, Proof},
  23. zkas::ZkBinary,
  24. };
  25. use darkfi_money_contract::{
  26. client::{build_half_swap_tx, EncryptedNote, Note},
  27. model::MoneyTransferParams,
  28. MoneyFunction, MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
  29. };
  30. use darkfi_sdk::{
  31. crypto::{
  32. contract_id::MONEY_CONTRACT_ID,
  33. pedersen::{pedersen_commitment_base, pedersen_commitment_u64, ValueBlind},
  34. poseidon_hash, PublicKey, SecretKey, TokenId,
  35. },
  36. pasta::pallas,
  37. tx::ContractCall,
  38. };
  39. use darkfi_serial::{deserialize, Encodable, SerialDecodable, SerialEncodable};
  40. use rand::rngs::OsRng;
  41. use super::Drk;
  42. #[derive(SerialEncodable, SerialDecodable)]
  43. /// Half of the swap data, includes the coin that is supposed to be sent,
  44. /// and the coin that is supposed to be received.
  45. pub struct PartialSwapData {
  46. params: MoneyTransferParams,
  47. proofs: Vec<Proof>,
  48. value_pair: (u64, u64),
  49. token_pair: (TokenId, TokenId),
  50. value_blinds: Vec<ValueBlind>,
  51. token_blinds: Vec<ValueBlind>,
  52. }
  53. impl Drk {
  54. /// Initialize the first half of an atomic swap
  55. pub async fn init_swap(
  56. &self,
  57. value_send: u64,
  58. token_send: TokenId,
  59. value_recv: u64,
  60. token_recv: TokenId,
  61. ) -> Result<PartialSwapData> {
  62. // First we'll fetch all of our unspent coins from the wallet.
  63. let mut owncoins = self.get_coins(false).await?;
  64. // Then we see if we have one that we can send.
  65. owncoins.retain(|x| {
  66. x.0.note.value == value_send &&
  67. x.0.note.token_id == token_send &&
  68. x.0.note.spend_hook == pallas::Base::zero()
  69. });
  70. if owncoins.is_empty() {
  71. return Err(anyhow!(
  72. "Did not find any unspent coins of value {} and token_id {}",
  73. value_send,
  74. token_send
  75. ))
  76. }
  77. // If there are any, we'll just spend the first one we see.
  78. let burn_coin = owncoins[0].0.clone();
  79. // Fetch our default address
  80. let address = self.wallet_address(1).await?;
  81. // We'll also need our Merkle tree
  82. let tree = self.get_money_tree().await?;
  83. let contract_id = *MONEY_CONTRACT_ID;
  84. // Now we need to do a lookup for the zkas proof bincodes, and create
  85. // the circuit objects and proving keys so we can build the transaction.
  86. // We also do this through the RPC.
  87. let zkas_bins = self.lookup_zkas(&contract_id).await?;
  88. let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1) else {
  89. return Err(anyhow!("Mint circuit not found"))
  90. };
  91. let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1) else {
  92. return Err(anyhow!("Burn circuit not found"))
  93. };
  94. let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
  95. let burn_zkbin = ZkBinary::decode(&burn_zkbin.1)?;
  96. let k = 13;
  97. let mint_circuit = ZkCircuit::new(empty_witnesses(&mint_zkbin), mint_zkbin.clone());
  98. let burn_circuit = ZkCircuit::new(empty_witnesses(&burn_zkbin), burn_zkbin.clone());
  99. eprintln!("Creating Mint circuit proving key");
  100. let mint_pk = ProvingKey::build(k, &mint_circuit);
  101. eprintln!("Creating Burn circuit proving key");
  102. let burn_pk = ProvingKey::build(k, &burn_circuit);
  103. // Now we should have everything we need to build the swap half
  104. eprintln!("Building first half of the swap transaction");
  105. let (half_params, half_proofs, _half_keys, _spent_coins, value_blinds, token_blinds) =
  106. build_half_swap_tx(
  107. &address,
  108. value_send,
  109. token_send,
  110. value_recv,
  111. token_recv,
  112. &[],
  113. &[],
  114. &[burn_coin],
  115. &tree,
  116. &mint_zkbin,
  117. &mint_pk,
  118. &burn_zkbin,
  119. &burn_pk,
  120. )?;
  121. // Now we have the half, so we can build `PartialSwapData` and return it.
  122. let ret = PartialSwapData {
  123. params: half_params,
  124. proofs: half_proofs,
  125. value_pair: (value_send, value_recv),
  126. token_pair: (token_send, token_recv),
  127. value_blinds,
  128. token_blinds,
  129. };
  130. Ok(ret)
  131. }
  132. /// Create a full transaction by inspecting and verifying given partial swap data,
  133. /// making the other half, and joining all this into a `Transaction` object.
  134. pub async fn join_swap(&self, partial: PartialSwapData) -> Result<Transaction> {
  135. // Our side of the tx in the pairs is the second half, so we try to find
  136. // an unspent coin like that in our wallet.
  137. let mut owncoins = self.get_coins(false).await?;
  138. owncoins.retain(|x| {
  139. x.0.note.value == partial.value_pair.1 && x.0.note.token_id == partial.token_pair.1
  140. });
  141. if owncoins.is_empty() {
  142. return Err(anyhow!(
  143. "Did not find any unspent coins of value {} and token_id {}",
  144. partial.value_pair.1,
  145. partial.token_pair.1
  146. ))
  147. }
  148. // If there are any, we'll just spend the first one we see.
  149. let burn_coin = owncoins[0].0.clone();
  150. // Fetch our default address
  151. let address = self.wallet_address(1).await?;
  152. // We'll also need our Merkle tree
  153. let tree = self.get_money_tree().await?;
  154. let contract_id = *MONEY_CONTRACT_ID;
  155. // Now we need to do a lookup for the zkas proof bincodes, and create
  156. // the circuit objects and proving keys so we can build the transaction.
  157. // We also do this through the RPC.
  158. let zkas_bins = self.lookup_zkas(&contract_id).await?;
  159. let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1) else {
  160. return Err(anyhow!("Mint circuit not found"))
  161. };
  162. let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1) else {
  163. return Err(anyhow!("Burn circuit not found"))
  164. };
  165. let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
  166. let burn_zkbin = ZkBinary::decode(&burn_zkbin.1)?;
  167. let k = 13;
  168. let mint_circuit = ZkCircuit::new(empty_witnesses(&mint_zkbin), mint_zkbin.clone());
  169. let burn_circuit = ZkCircuit::new(empty_witnesses(&burn_zkbin), burn_zkbin.clone());
  170. eprintln!("Creating Mint circuit proving key");
  171. let mint_pk = ProvingKey::build(k, &mint_circuit);
  172. eprintln!("Creating Burn circuit proving key");
  173. let burn_pk = ProvingKey::build(k, &burn_circuit);
  174. // TODO: Maybe some kind of verification at this point
  175. // Now we should have everything we need to build the swap half
  176. eprintln!("Building second half of the swap transaction");
  177. let (half_params, half_proofs, half_keys, _spent_coins, _value_blinds, _token_blinds) =
  178. build_half_swap_tx(
  179. &address,
  180. partial.value_pair.1,
  181. partial.token_pair.1,
  182. partial.value_pair.0,
  183. partial.token_pair.0,
  184. &partial.value_blinds,
  185. &partial.token_blinds,
  186. &[burn_coin],
  187. &tree,
  188. &mint_zkbin,
  189. &mint_pk,
  190. &burn_zkbin,
  191. &burn_pk,
  192. )?;
  193. let full_params = MoneyTransferParams {
  194. clear_inputs: vec![],
  195. inputs: vec![partial.params.inputs[0].clone(), half_params.inputs[0].clone()],
  196. outputs: vec![partial.params.outputs[0].clone(), half_params.outputs[0].clone()],
  197. };
  198. let full_proofs = vec![
  199. partial.proofs[0].clone(),
  200. half_proofs[0].clone(),
  201. partial.proofs[1].clone(),
  202. half_proofs[1].clone(),
  203. ];
  204. let mut data = vec![MoneyFunction::OtcSwap as u8];
  205. full_params.encode(&mut data)?;
  206. let mut tx = Transaction {
  207. calls: vec![ContractCall { contract_id, data }],
  208. proofs: vec![full_proofs],
  209. signatures: vec![],
  210. };
  211. eprintln!("Signing swap transaction");
  212. let sigs = tx.create_sigs(&mut OsRng, &half_keys)?;
  213. tx.signatures = vec![sigs];
  214. Ok(tx)
  215. }
  216. /// Inspect and verify a given swap (half or full) transaction
  217. pub async fn inspect_swap(&self, bytes: Vec<u8>) -> Result<()> {
  218. let mut full: Option<Transaction> = None;
  219. let mut _half: Option<PartialSwapData> = None;
  220. if let Ok(v) = deserialize(&bytes) {
  221. full = Some(v)
  222. };
  223. match deserialize(&bytes) {
  224. Ok(v) => _half = Some(v),
  225. Err(_) => {
  226. if full.is_none() {
  227. return Err(anyhow!("Failed to deserialize to Transaction or PartialSwapData"))
  228. }
  229. }
  230. }
  231. if let Some(tx) = full {
  232. // We're inspecting a full transaction
  233. if tx.calls.len() != 1 {
  234. eprintln!(
  235. "Found {} contract calls in the transaction, there should be 1",
  236. tx.calls.len()
  237. );
  238. return Err(anyhow!("Inspection failed"))
  239. }
  240. let params: MoneyTransferParams = deserialize(&tx.calls[0].data[1..])?;
  241. eprintln!("Parameters:\n{:#?}", params);
  242. if params.inputs.len() != 2 {
  243. eprintln!("Found {} inputs, there should be 2", params.inputs.len());
  244. return Err(anyhow!("Inspection failed"))
  245. }
  246. if params.outputs.len() != 2 {
  247. eprintln!("Found {} outputs, there should be 2", params.outputs.len());
  248. return Err(anyhow!("Inspection failed"))
  249. }
  250. // Try to decrypt one of the outputs.
  251. let secret_keys = self.get_money_secrets().await?;
  252. let mut skey: Option<SecretKey> = None;
  253. let mut note: Option<Note> = None;
  254. let mut output_idx = 0;
  255. for output in &params.outputs {
  256. let ciphertext = output.ciphertext.clone();
  257. let ephem_public = output.ephem_public;
  258. let e_note = EncryptedNote { ciphertext, ephem_public };
  259. eprintln!("Trying to decrypt note in output {}", output_idx);
  260. for secret in &secret_keys {
  261. if let Ok(d_note) = e_note.decrypt(secret) {
  262. let s: SecretKey = deserialize(&d_note.memo)?;
  263. skey = Some(s);
  264. note = Some(d_note);
  265. eprintln!("Successfully decrypted and found an ephemeral secret");
  266. break
  267. }
  268. }
  269. if note.is_some() {
  270. break
  271. }
  272. output_idx += 1;
  273. }
  274. let Some(note) = note else {
  275. eprintln!("Error: Could not decrypt notes of either output");
  276. return Err(anyhow!("Inspection failed"))
  277. };
  278. eprintln!(
  279. "Output[{}] value: {} ({})",
  280. output_idx,
  281. note.value,
  282. encode_base10(note.value, 8)
  283. );
  284. eprintln!("Output[{}] token ID: {}", output_idx, note.token_id);
  285. let skey = skey.unwrap();
  286. let (pub_x, pub_y) = PublicKey::from_secret(skey).xy();
  287. let coin = poseidon_hash([
  288. pub_x,
  289. pub_y,
  290. pallas::Base::from(note.value),
  291. note.token_id.inner(),
  292. note.serial,
  293. note.coin_blind,
  294. ]);
  295. if coin == params.outputs[output_idx].coin {
  296. eprintln!("Output[{}] coin matches decrypted note metadata", output_idx);
  297. } else {
  298. eprintln!("Error: Output[{}] coin does not match note metadata", output_idx);
  299. return Err(anyhow!("Inspection failed"))
  300. }
  301. let valcom = pedersen_commitment_u64(note.value, note.value_blind);
  302. let tokcom = pedersen_commitment_base(note.token_id.inner(), note.token_blind);
  303. if valcom != params.outputs[output_idx].value_commit {
  304. eprintln!(
  305. "Error: Output[{}] value commitment does not match note metadata",
  306. output_idx
  307. );
  308. return Err(anyhow!("Inspection failed"))
  309. }
  310. if tokcom != params.outputs[output_idx].token_commit {
  311. eprintln!(
  312. "Error: Output[{}] token commitment does not match note metadata",
  313. output_idx
  314. );
  315. return Err(anyhow!("Inspection failed"))
  316. }
  317. eprintln!("Value and token commitments match decrypted note metadata");
  318. // Verify that the output commitments match the other input commitments
  319. match output_idx {
  320. 0 => {
  321. if valcom != params.inputs[1].value_commit ||
  322. tokcom != params.inputs[1].token_commit
  323. {
  324. eprintln!("Error: Value/Token commits of output[0] do not match input[1]");
  325. return Err(anyhow!("Inspection failed"))
  326. }
  327. }
  328. 1 => {
  329. if valcom != params.inputs[0].value_commit ||
  330. tokcom != params.inputs[0].token_commit
  331. {
  332. eprintln!("Error: Value/Token commits of output[1] do not match input[0]");
  333. return Err(anyhow!("Inspection failed"))
  334. }
  335. }
  336. _ => unreachable!(),
  337. }
  338. eprintln!("Found matching pedersen commitments for outputs and inputs");
  339. // TODO: Verify signature
  340. // TODO: Verify ZK proofs
  341. return Ok(())
  342. }
  343. // TODO: Inspect PartialSwapData
  344. todo!("Inspect PartialSwapData");
  345. }
  346. /// Sign a given transaction by retrieving the secret key from the encrypted
  347. /// note and prepending it to the transaction's signatures.
  348. pub async fn sign_swap(&self, tx: &mut Transaction) -> Result<()> {
  349. // We need our secret keys to try and decrypt the note
  350. let secret_keys = self.get_money_secrets().await?;
  351. let params: MoneyTransferParams = deserialize(&tx.calls[0].data[1..])?;
  352. // Our output should be outputs[0] so we try to decrypt that.
  353. let ciphertext = params.outputs[0].ciphertext.clone();
  354. let ephem_public = params.outputs[0].ephem_public;
  355. let encrypted_note = EncryptedNote { ciphertext, ephem_public };
  356. eprintln!("Trying to decrypt note in outputs[0]");
  357. let mut skey = None;
  358. for secret in &secret_keys {
  359. if let Ok(note) = encrypted_note.decrypt(secret) {
  360. let s: SecretKey = deserialize(&note.memo)?;
  361. eprintln!("Successfully decrypted and found an ephemeral secret");
  362. skey = Some(s);
  363. break
  364. }
  365. }
  366. let Some(skey) = skey else {
  367. eprintln!("Error: Failed to decrypt note with any of our secret keys");
  368. return Err(anyhow!("Failed to decrypt note with any of our secret keys"))
  369. };
  370. eprintln!("Signing swap transaction");
  371. let sigs = tx.create_sigs(&mut OsRng, &[skey])?;
  372. tx.signatures[0].insert(0, sigs[0]);
  373. Ok(())
  374. }
  375. }