builder.rs 5.8 KB

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