main.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  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 std::{
  19. io::{stdin, Read},
  20. process::exit,
  21. };
  22. use clap::{Parser, Subcommand};
  23. use darkfi_sdk::crypto::{
  24. pedersen::{pedersen_commitment_base, pedersen_commitment_u64},
  25. schnorr,
  26. schnorr::SchnorrSecret,
  27. PublicKey, SecretKey, TokenId,
  28. };
  29. use darkfi_serial::{deserialize, serialize, SerialDecodable, SerialEncodable};
  30. use halo2_proofs::arithmetic::Field;
  31. use rand::rngs::OsRng;
  32. use url::Url;
  33. use darkfi::{
  34. cli_desc,
  35. crypto::{
  36. burn_proof::{create_burn_proof, verify_burn_proof},
  37. mint_proof::{create_mint_proof, verify_mint_proof},
  38. note::{EncryptedNote, Note},
  39. proof::{ProvingKey, VerifyingKey},
  40. types::{
  41. DrkCoinBlind, DrkSerial, DrkSpendHook, DrkUserData, DrkUserDataBlind, DrkValueBlind,
  42. },
  43. BurnRevealedValues, MintRevealedValues, Proof,
  44. },
  45. rpc::client::RpcClient,
  46. tx::{
  47. partial::{PartialTransaction, PartialTransactionInput},
  48. Transaction, TransactionInput, TransactionOutput,
  49. },
  50. util::{
  51. cli::{fg_green, fg_red, progress_bar},
  52. parse::encode_base10,
  53. },
  54. zk::circuit::{BurnContract, MintContract},
  55. Result,
  56. };
  57. mod cli_util;
  58. use cli_util::{parse_token_pair, parse_value_pair};
  59. mod rpc;
  60. use rpc::Rpc;
  61. #[derive(Parser)]
  62. #[clap(name = "darkotc", about = cli_desc!(), version)]
  63. #[clap(arg_required_else_help(true))]
  64. struct Args {
  65. #[clap(short, parse(from_occurrences))]
  66. /// Increase verbosity (-vvv supported)
  67. verbose: u8,
  68. #[clap(short, long, default_value = "tcp://127.0.0.1:8340")]
  69. /// darkfid JSON-RPC endpoint
  70. endpoint: Url,
  71. #[clap(subcommand)]
  72. command: Subcmd,
  73. }
  74. #[derive(Subcommand)]
  75. enum Subcmd {
  76. /// Initialize an atomic swap
  77. Init {
  78. #[clap(short, long)]
  79. /// Pair of token IDs to swap: token_to_send:token_to_recv
  80. token_pair: String,
  81. #[clap(short, long)]
  82. /// Pair of values to swap: value_to_send:value_to_recv
  83. value_pair: String,
  84. },
  85. /// Inspect partial swap data from stdin.
  86. InspectPartial,
  87. /// Join two partial swap data files and build a tx
  88. Join { data0: String, data1: String },
  89. /// Sign a transaction given from stdin.
  90. SignTx,
  91. }
  92. #[derive(SerialEncodable, SerialDecodable)]
  93. /// Half of the swap data, includes the coin that is supposed to be received,
  94. /// and the coin that is supposed to be sent.
  95. struct PartialSwapData {
  96. /// Mint proof of coin to be received
  97. mint_proof: Proof,
  98. /// Public values for the mint proof
  99. mint_revealed: MintRevealedValues,
  100. /// Value of the coin to be received
  101. mint_value: u64,
  102. /// Token ID of the coin to be received
  103. mint_token: TokenId,
  104. /// Blinding factor for the minted value pedersen commitment
  105. mint_value_blind: DrkValueBlind,
  106. /// Blinding factor for the minted token ID pedersen commitment
  107. mint_token_blind: DrkValueBlind,
  108. /// Burn proof of the coin to be sent
  109. burn_proof: Proof,
  110. /// Public values for the burn proof
  111. burn_revealed: BurnRevealedValues,
  112. /// Value of the coin to be sent
  113. burn_value: u64,
  114. /// Token ID of the coin to be sent
  115. burn_token: TokenId,
  116. /// Blinding factor for the burned value pedersen commitment
  117. burn_value_blind: DrkValueBlind,
  118. /// Blinding factor for the burned token ID pedersen commitment
  119. burn_token_blind: DrkValueBlind,
  120. /// Encrypted note
  121. encrypted_note: EncryptedNote,
  122. }
  123. #[derive(SerialEncodable, SerialDecodable)]
  124. /// Full swap data, containing two instances of `PartialSwapData`, which
  125. /// represent an atomic swap.
  126. struct SwapData {
  127. swap0: PartialSwapData,
  128. swap1: PartialSwapData,
  129. }
  130. async fn init_swap(
  131. endpoint: Url,
  132. token_pair: (TokenId, TokenId),
  133. value_pair: (u64, u64),
  134. ) -> Result<PartialSwapData> {
  135. let rpc_client = match RpcClient::new(endpoint).await {
  136. Ok(v) => v,
  137. Err(e) => {
  138. eprintln!("Error: Failed connecting to darkfid JSON-RPC endpoint.");
  139. return Err(e)
  140. }
  141. };
  142. let rpc = Rpc { rpc_client };
  143. // TODO: Implement metadata for decimals, don't hardcode.
  144. let vp = value_pair;
  145. // Connect to darkfid and see if there's available funds.
  146. let balance = rpc.balance_of(token_pair.0).await?;
  147. if balance < vp.0 {
  148. eprintln!(
  149. "Error: There's not enough balance for token \"{}\" in your wallet.",
  150. token_pair.0
  151. );
  152. eprintln!("Available balance is {} ({})", encode_base10(balance, 8), balance);
  153. exit(1);
  154. }
  155. // If there's not enough funds in a single coin, mint a single new coin
  156. // with the funds. We do this to minimize the size of the swap transaction.
  157. // i.e. 2 inputs and 2 outputs.
  158. // TODO: Implement ^
  159. // TODO: Maybe this should be done by the user beforehand?
  160. // Find a coin to spend. We can find multiple, but we'll pick the first one.
  161. let coins = rpc.get_coins_valtok(vp.0, token_pair.0).await?;
  162. if coins.is_empty() {
  163. eprintln!("Error: Did not manage to find a coin with enough value to spend.");
  164. exit(1);
  165. }
  166. // Fetch our default address
  167. let our_addr = rpc.wallet_address().await?;
  168. let our_pubk = match PublicKey::try_from(our_addr) {
  169. Ok(v) => v,
  170. Err(e) => {
  171. eprintln!("Error converting our address into PublicKey: {}", e);
  172. exit(1);
  173. }
  174. };
  175. // Build ZK proving keys
  176. let pb = progress_bar("Building proving key for the Mint contract");
  177. let mint_pk = ProvingKey::build(11, &MintContract::default());
  178. pb.finish();
  179. let pb = progress_bar("Building proving key for the Burn contract");
  180. let burn_pk = ProvingKey::build(11, &BurnContract::default());
  181. pb.finish();
  182. // The coin we want to receive
  183. let recv_value_blind = DrkValueBlind::random(&mut OsRng);
  184. let recv_token_blind = DrkValueBlind::random(&mut OsRng);
  185. let recv_coin_blind = DrkCoinBlind::random(&mut OsRng);
  186. let recv_serial = DrkSerial::random(&mut OsRng);
  187. // Spend hook and user data disabled
  188. let spend_hook = DrkSpendHook::from(0);
  189. let user_data = DrkUserData::from(0);
  190. let pb = progress_bar("Building Mint proof for the receiving coin");
  191. let (mint_proof, mint_revealed) = create_mint_proof(
  192. &mint_pk,
  193. vp.1,
  194. token_pair.1,
  195. recv_value_blind,
  196. recv_token_blind,
  197. recv_serial,
  198. spend_hook,
  199. user_data,
  200. recv_coin_blind,
  201. our_pubk,
  202. )?;
  203. pb.finish();
  204. // The coin we are spending.
  205. let coin = coins[0].clone();
  206. let pb = progress_bar("Building Burn proof for the spending coin");
  207. let signature_secret = SecretKey::random(&mut OsRng);
  208. let merkle_path = match rpc.get_merkle_path(usize::from(coin.leaf_position)).await {
  209. Ok(v) => v,
  210. Err(e) => {
  211. eprintln!("Failed to get Merkle path for our coin from darkfid RPC: {}", e);
  212. exit(1);
  213. }
  214. };
  215. // Spend hook and user data disabled
  216. let spend_hook = DrkSpendHook::from(0);
  217. let user_data = DrkUserData::from(0);
  218. let user_data_blind = DrkUserDataBlind::random(&mut OsRng);
  219. let (burn_proof, burn_revealed) = create_burn_proof(
  220. &burn_pk,
  221. vp.0,
  222. token_pair.0,
  223. coin.note.value_blind,
  224. coin.note.token_blind,
  225. coin.note.serial,
  226. spend_hook,
  227. user_data,
  228. user_data_blind,
  229. coin.note.coin_blind,
  230. coin.secret,
  231. coin.leaf_position,
  232. merkle_path,
  233. signature_secret,
  234. )?;
  235. pb.finish();
  236. // Create encrypted note
  237. let note = Note {
  238. serial: recv_serial,
  239. value: vp.1,
  240. token_id: token_pair.1,
  241. coin_blind: recv_coin_blind,
  242. value_blind: recv_value_blind,
  243. token_blind: recv_token_blind,
  244. // Here we store our secret key we used for signing
  245. memo: serialize(&signature_secret),
  246. };
  247. let encrypted_note = note.encrypt(&our_pubk)?;
  248. // Pack proofs together with pedersen commitment openings so
  249. // counterparty can verify correctness.
  250. let partial_swap_data = PartialSwapData {
  251. mint_proof,
  252. mint_revealed,
  253. mint_value: vp.1,
  254. mint_token: token_pair.1,
  255. mint_value_blind: recv_value_blind,
  256. mint_token_blind: recv_token_blind,
  257. burn_proof,
  258. burn_value: vp.0,
  259. burn_token: token_pair.0,
  260. burn_revealed,
  261. burn_value_blind: coin.note.value_blind,
  262. burn_token_blind: coin.note.token_blind,
  263. encrypted_note,
  264. };
  265. Ok(partial_swap_data)
  266. }
  267. fn inspect_partial(data: &str) -> Result<()> {
  268. let bytes = match bs58::decode(data).into_vec() {
  269. Ok(v) => v,
  270. Err(e) => {
  271. eprintln!("Error decoding base58 data from input: {}", e);
  272. exit(1);
  273. }
  274. };
  275. let sd: PartialSwapData = match deserialize(&bytes) {
  276. Ok(v) => v,
  277. Err(e) => {
  278. eprintln!("Error deserializing partial swap data into struct: {}", e);
  279. exit(1);
  280. }
  281. };
  282. eprintln!("Successfully decoded partial swap data");
  283. // Build ZK verifying keys
  284. let pb = progress_bar("Building verifying key for the Mint contract");
  285. let mint_vk = VerifyingKey::build(11, &MintContract::default());
  286. pb.finish();
  287. let pb = progress_bar("Building verifying key for the Burn contract");
  288. let burn_vk = VerifyingKey::build(11, &BurnContract::default());
  289. pb.finish();
  290. let pb = progress_bar("Verifying Burn proof");
  291. let burn_valid = verify_burn_proof(&burn_vk, &sd.burn_proof, &sd.burn_revealed).is_ok();
  292. pb.finish();
  293. let pb = progress_bar("Verifying Mint proof");
  294. let mint_valid = verify_mint_proof(&mint_vk, &sd.mint_proof, &sd.mint_revealed).is_ok();
  295. pb.finish();
  296. eprintln!(" Verifying Pedersen commitments");
  297. let burn_value_valid = pedersen_commitment_u64(sd.burn_value, sd.burn_value_blind) ==
  298. sd.burn_revealed.value_commit;
  299. let burn_token_valid = pedersen_commitment_base(sd.burn_token.inner(), sd.burn_token_blind) ==
  300. sd.burn_revealed.token_commit;
  301. let mint_value_valid = pedersen_commitment_u64(sd.mint_value, sd.mint_value_blind) ==
  302. sd.mint_revealed.value_commit;
  303. let mint_token_valid = pedersen_commitment_base(sd.mint_token.inner(), sd.mint_token_blind) ==
  304. sd.mint_revealed.token_commit;
  305. let mut valid = true;
  306. eprintln!("Summary:");
  307. eprint!(" Burn proof: ");
  308. if burn_valid {
  309. eprintln!("{}", fg_green("VALID"));
  310. } else {
  311. eprintln!("{}", fg_red("INVALID"));
  312. valid = false;
  313. }
  314. eprint!(" Burn proof value commitment: ");
  315. if burn_value_valid {
  316. eprintln!("{}", fg_green("VALID"));
  317. } else {
  318. eprintln!("{}", fg_red("INVALID"));
  319. valid = false;
  320. }
  321. eprint!(" Burn proof token commitment: ");
  322. if burn_token_valid {
  323. eprintln!("{}", fg_green("VALID"));
  324. } else {
  325. eprintln!("{}", fg_red("INVALID"));
  326. valid = false;
  327. }
  328. eprint!(" Mint proof: ");
  329. if mint_valid {
  330. eprintln!("{}", fg_green("VALID"));
  331. } else {
  332. eprintln!("{}", fg_red("INVALID"));
  333. valid = false;
  334. }
  335. eprint!(" Mint proof value commitment: ");
  336. if mint_value_valid {
  337. eprintln!("{}", fg_green("VALID"));
  338. } else {
  339. eprintln!("{}", fg_red("INVALID"));
  340. valid = false;
  341. }
  342. eprint!(" Mint proof token commitment: ");
  343. if mint_token_valid {
  344. eprintln!("{}", fg_green("VALID"));
  345. } else {
  346. eprintln!("{}", fg_red("INVALID"));
  347. valid = false;
  348. }
  349. eprintln!("========================================");
  350. eprintln!("Mint: {} {}", encode_base10(sd.mint_value, 8), sd.mint_token);
  351. eprintln!("Burn: {} {}", encode_base10(sd.burn_value, 8), sd.burn_token);
  352. eprint!("\nThe ZK proofs and commitments inspected are ");
  353. if !valid {
  354. println!("{}", fg_red("NOT VALID"));
  355. exit(1);
  356. } else {
  357. eprintln!("{}", fg_green("VALID"));
  358. }
  359. Ok(())
  360. }
  361. async fn join(endpoint: Url, d0: PartialSwapData, d1: PartialSwapData) -> Result<Transaction> {
  362. eprintln!("Joining data into a transaction");
  363. let input0 = PartialTransactionInput { burn_proof: d0.burn_proof, revealed: d0.burn_revealed };
  364. let input1 = PartialTransactionInput { burn_proof: d1.burn_proof, revealed: d1.burn_revealed };
  365. let inputs = vec![input0, input1];
  366. let output0 = TransactionOutput {
  367. mint_proof: d0.mint_proof,
  368. revealed: d0.mint_revealed,
  369. enc_note: d0.encrypted_note.clone(),
  370. };
  371. let output1 = TransactionOutput {
  372. mint_proof: d1.mint_proof,
  373. revealed: d1.mint_revealed,
  374. enc_note: d1.encrypted_note.clone(),
  375. };
  376. let outputs = vec![output0, output1];
  377. let partial_tx = PartialTransaction { clear_inputs: vec![], inputs, outputs };
  378. let unsigned_tx_data = serialize(&partial_tx);
  379. let mut inputs = vec![];
  380. let mut signed: bool;
  381. eprint!("Trying to decrypt the note of the first half... ");
  382. let rpc_client = RpcClient::new(endpoint.clone()).await?;
  383. let rpc = Rpc { rpc_client };
  384. let note = match rpc.decrypt_note(&d0.encrypted_note).await {
  385. Ok(v) => v,
  386. Err(_) => None,
  387. };
  388. if let Some(note) = note {
  389. eprintln!("{}", fg_green("Success"));
  390. let signature = try_sign_tx(&note, &unsigned_tx_data[..])?;
  391. let input = TransactionInput::from_partial(partial_tx.inputs[0].clone(), signature);
  392. inputs.push(input);
  393. signed = true;
  394. } else {
  395. eprintln!("{}", fg_red("Failure"));
  396. let signature = schnorr::Signature::dummy();
  397. let input = TransactionInput::from_partial(partial_tx.inputs[0].clone(), signature);
  398. inputs.push(input);
  399. signed = false;
  400. }
  401. // If we have signed, we shouldn't have to look in the other one, but we might
  402. // be sending to ourself for some reason.
  403. eprint!("Trying to decrypt the note of the second half... ");
  404. let rpc_client = RpcClient::new(endpoint).await?;
  405. let rpc = Rpc { rpc_client };
  406. let note = match rpc.decrypt_note(&d1.encrypted_note).await {
  407. Ok(v) => v,
  408. Err(_) => None,
  409. };
  410. if let Some(note) = note {
  411. eprintln!("{}", fg_green("Success"));
  412. let signature = try_sign_tx(&note, &unsigned_tx_data[..])?;
  413. let input = TransactionInput::from_partial(partial_tx.inputs[1].clone(), signature);
  414. inputs.push(input);
  415. signed = true;
  416. } else {
  417. eprintln!("{}", fg_red("Failure"));
  418. let signature = schnorr::Signature::dummy();
  419. let input = TransactionInput::from_partial(partial_tx.inputs[1].clone(), signature);
  420. inputs.push(input);
  421. if !signed {
  422. eprintln!("Error: Failed to sign transaction!");
  423. exit(1);
  424. }
  425. }
  426. if !signed {
  427. eprintln!("Error: Failed to sign transaction!");
  428. exit(1);
  429. }
  430. let tx = Transaction { clear_inputs: vec![], inputs, outputs: partial_tx.outputs };
  431. Ok(tx)
  432. }
  433. async fn sign_tx(endpoint: Url, data: &str) -> Result<Transaction> {
  434. eprintln!("Trying to sign transaction");
  435. let mut tx: Transaction = deserialize(&bs58::decode(data).into_vec()?)?;
  436. // We assume our input and our output are in the same index, since this
  437. // transaction contains 2 inputs and 2 outputs, and one of each is ours,
  438. // and one of each is the other party's. So we go on and sign the input
  439. // index of the output index we can decrypt the note for.
  440. let mut idx_to_sign = 0;
  441. let mut signature = schnorr::Signature::dummy();
  442. eprintln!("Looking for an encrypted note we can decrypt...");
  443. let mut found_secret = false;
  444. for (i, output) in tx.outputs.iter().enumerate() {
  445. // TODO: FIXME: Consider not closing the RPC on failure.
  446. let rpc = Rpc { rpc_client: RpcClient::new(endpoint.clone()).await? };
  447. let note = match rpc.decrypt_note(&output.enc_note).await {
  448. Ok(v) => v,
  449. Err(_) => continue,
  450. };
  451. if let Some(note) = note {
  452. eprintln!("Successfully decrypted note in output {}", i);
  453. eprintln!("Creating signature...");
  454. let mut unsigned_tx_data = vec![];
  455. let _ = tx.encode_without_signature(&mut unsigned_tx_data)?;
  456. signature = try_sign_tx(&note, &unsigned_tx_data[..])?;
  457. found_secret = true;
  458. idx_to_sign = i;
  459. break
  460. }
  461. eprintln!("Failed to find a note to decrypt. Signing failed.");
  462. exit(1);
  463. }
  464. if !found_secret {
  465. eprintln!("Error: Did not manage to sign transaction. Couldn't find any secret keys.");
  466. exit(1);
  467. }
  468. tx.inputs[idx_to_sign].signature = signature;
  469. Ok(tx)
  470. }
  471. fn try_sign_tx(note: &Note, tx_data: &[u8]) -> Result<schnorr::Signature> {
  472. if note.memo.len() != 32 {
  473. eprintln!("Error: The note memo is not 32 bytes");
  474. exit(1);
  475. }
  476. let secret = match SecretKey::from_bytes(note.memo.clone().try_into().unwrap()) {
  477. Ok(v) => v,
  478. Err(e) => {
  479. eprintln!("Did not manage to cast bytes into SecretKey: {}", e);
  480. exit(1);
  481. }
  482. };
  483. eprintln!("Signing transaction...");
  484. let signature = secret.sign(&mut OsRng, tx_data);
  485. Ok(signature)
  486. }
  487. #[async_std::main]
  488. async fn main() -> Result<()> {
  489. let args = Args::parse();
  490. match args.command {
  491. Subcmd::Init { token_pair, value_pair } => {
  492. let token_pair = parse_token_pair(&token_pair)?;
  493. let value_pair = parse_value_pair(&value_pair)?;
  494. eprintln!("Creating half of an atomic swap");
  495. eprintln!("Send: {} {} tokens.", encode_base10(value_pair.0, 8), token_pair.0);
  496. eprintln!("Recv: {} {} tokens.", encode_base10(value_pair.1, 8), token_pair.1);
  497. let swap_data = init_swap(args.endpoint, token_pair, value_pair).await?;
  498. println!("{}", bs58::encode(serialize(&swap_data)).into_string());
  499. Ok(())
  500. }
  501. Subcmd::InspectPartial => {
  502. let mut buf = String::new();
  503. stdin().read_to_string(&mut buf)?;
  504. inspect_partial(buf.trim())
  505. }
  506. Subcmd::Join { data0, data1 } => {
  507. let d0 = std::fs::read_to_string(data0)?;
  508. let d1 = std::fs::read_to_string(data1)?;
  509. let d0 = deserialize(&bs58::decode(&d0.trim()).into_vec()?)?;
  510. let d1 = deserialize(&bs58::decode(&d1.trim()).into_vec()?)?;
  511. let tx = join(args.endpoint, d0, d1).await?;
  512. println!("{}", bs58::encode(&serialize(&tx)).into_string());
  513. eprintln!("Successfully signed transaction");
  514. Ok(())
  515. }
  516. Subcmd::SignTx => {
  517. let mut buf = String::new();
  518. stdin().read_to_string(&mut buf)?;
  519. let tx = sign_tx(args.endpoint, buf.trim()).await?;
  520. println!("{}", bs58::encode(&serialize(&tx)).into_string());
  521. eprintln!("Successfully signed transaction");
  522. Ok(())
  523. }
  524. }
  525. }