builder.rs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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::{schnorr::SchnorrSecret, MerkleNode, PublicKey, SecretKey, TokenId};
  19. use darkfi_serial::serialize;
  20. use pasta_curves::group::ff::Field;
  21. use rand::rngs::OsRng;
  22. use super::{
  23. partial::{PartialTransaction, PartialTransactionClearInput, PartialTransactionInput},
  24. Transaction, TransactionClearInput, TransactionInput, TransactionOutput,
  25. };
  26. use crate::{
  27. crypto::{
  28. burn_proof::create_burn_proof,
  29. mint_proof::create_mint_proof,
  30. note::Note,
  31. proof::ProvingKey,
  32. types::{
  33. DrkCoinBlind, DrkSerial, DrkSpendHook, DrkUserData, DrkUserDataBlind, DrkValueBlind,
  34. },
  35. },
  36. Result,
  37. };
  38. pub struct TransactionBuilder {
  39. pub clear_inputs: Vec<TransactionBuilderClearInputInfo>,
  40. pub inputs: Vec<TransactionBuilderInputInfo>,
  41. pub outputs: Vec<TransactionBuilderOutputInfo>,
  42. }
  43. pub struct TransactionBuilderClearInputInfo {
  44. pub value: u64,
  45. pub token_id: TokenId,
  46. pub signature_secret: SecretKey,
  47. }
  48. pub struct TransactionBuilderInputInfo {
  49. pub leaf_position: incrementalmerkletree::Position,
  50. pub merkle_path: Vec<MerkleNode>,
  51. pub secret: SecretKey,
  52. pub note: Note,
  53. }
  54. pub struct TransactionBuilderOutputInfo {
  55. pub value: u64,
  56. pub token_id: TokenId,
  57. pub public: PublicKey,
  58. }
  59. impl TransactionBuilder {
  60. fn compute_remainder_blind(
  61. clear_inputs: &[PartialTransactionClearInput],
  62. input_blinds: &[DrkValueBlind],
  63. output_blinds: &[DrkValueBlind],
  64. ) -> DrkValueBlind {
  65. let mut total = DrkValueBlind::zero();
  66. for input in clear_inputs {
  67. total += input.value_blind;
  68. }
  69. for input_blind in input_blinds {
  70. total += input_blind;
  71. }
  72. for output_blind in output_blinds {
  73. total -= output_blind;
  74. }
  75. total
  76. }
  77. pub fn build(self, mint_pk: &ProvingKey, burn_pk: &ProvingKey) -> Result<Transaction> {
  78. assert!(self.clear_inputs.len() + self.inputs.len() > 0);
  79. let mut clear_inputs = vec![];
  80. let token_blind = DrkValueBlind::random(&mut OsRng);
  81. for input in &self.clear_inputs {
  82. let signature_public = PublicKey::from_secret(input.signature_secret);
  83. let value_blind = DrkValueBlind::random(&mut OsRng);
  84. let clear_input = PartialTransactionClearInput {
  85. value: input.value,
  86. token_id: input.token_id,
  87. value_blind,
  88. token_blind,
  89. signature_public,
  90. };
  91. clear_inputs.push(clear_input);
  92. }
  93. let mut inputs = vec![];
  94. let mut input_blinds = vec![];
  95. let mut signature_secrets = vec![];
  96. for input in self.inputs {
  97. let value_blind = DrkValueBlind::random(&mut OsRng);
  98. input_blinds.push(value_blind);
  99. let signature_secret = SecretKey::random(&mut OsRng);
  100. // Disable composability for this old obselete API
  101. let spend_hook = DrkSpendHook::from(0);
  102. let user_data = DrkUserData::from(0);
  103. let user_data_blind = DrkUserDataBlind::random(&mut OsRng);
  104. let (proof, revealed) = create_burn_proof(
  105. burn_pk,
  106. input.note.value,
  107. input.note.token_id,
  108. value_blind,
  109. token_blind,
  110. input.note.serial,
  111. spend_hook,
  112. user_data,
  113. user_data_blind,
  114. input.note.coin_blind,
  115. input.secret,
  116. input.leaf_position,
  117. input.merkle_path,
  118. signature_secret,
  119. )?;
  120. // First we make the tx then sign after
  121. signature_secrets.push(signature_secret);
  122. let input = PartialTransactionInput { burn_proof: proof, revealed };
  123. inputs.push(input);
  124. }
  125. let mut outputs = vec![];
  126. let mut output_blinds = vec![];
  127. // This value_blind calc assumes there will always be at least a single output
  128. assert!(!self.outputs.is_empty());
  129. for (i, output) in self.outputs.iter().enumerate() {
  130. let value_blind = if i == self.outputs.len() - 1 {
  131. Self::compute_remainder_blind(&clear_inputs, &input_blinds, &output_blinds)
  132. } else {
  133. DrkValueBlind::random(&mut OsRng)
  134. };
  135. output_blinds.push(value_blind);
  136. let serial = DrkSerial::random(&mut OsRng);
  137. let coin_blind = DrkCoinBlind::random(&mut OsRng);
  138. // Disable composability for this old obselete API
  139. let spend_hook = DrkSpendHook::from(0);
  140. let user_data = DrkUserData::from(0);
  141. let (mint_proof, revealed) = create_mint_proof(
  142. mint_pk,
  143. output.value,
  144. output.token_id,
  145. value_blind,
  146. token_blind,
  147. serial,
  148. spend_hook,
  149. user_data,
  150. coin_blind,
  151. output.public,
  152. )?;
  153. // Encrypted note
  154. let note = Note {
  155. serial,
  156. value: output.value,
  157. token_id: output.token_id,
  158. coin_blind,
  159. value_blind,
  160. token_blind,
  161. memo: vec![],
  162. };
  163. let encrypted_note = note.encrypt(&output.public)?;
  164. let output = TransactionOutput { mint_proof, revealed, enc_note: encrypted_note };
  165. outputs.push(output);
  166. }
  167. let partial_tx = PartialTransaction { clear_inputs, inputs, outputs };
  168. let unsigned_tx_data = serialize(&partial_tx);
  169. let mut clear_inputs = vec![];
  170. for (input, info) in partial_tx.clear_inputs.into_iter().zip(self.clear_inputs) {
  171. let secret = info.signature_secret;
  172. let signature = secret.sign(&mut OsRng, &unsigned_tx_data);
  173. let input = TransactionClearInput::from_partial(input, signature);
  174. clear_inputs.push(input);
  175. }
  176. let mut inputs = vec![];
  177. for (input, signature_secret) in
  178. partial_tx.inputs.into_iter().zip(signature_secrets.into_iter())
  179. {
  180. let signature = signature_secret.sign(&mut OsRng, &unsigned_tx_data);
  181. let input = TransactionInput::from_partial(input, signature);
  182. inputs.push(input);
  183. }
  184. Ok(Transaction { clear_inputs, inputs, outputs: partial_tx.outputs })
  185. }
  186. }