builder.rs 6.5 KB

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