builder.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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. keypair::{PublicKey, SecretKey},
  10. merkle_node::MerkleNode,
  11. mint_proof::create_mint_proof,
  12. note::Note,
  13. proof::ProvingKey,
  14. schnorr::SchnorrSecret,
  15. spend_proof::create_spend_proof,
  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, spend_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. input_blinds.push(input.note.value_blind);
  80. let signature_secret = SecretKey::random(&mut OsRng);
  81. let (proof, revealed) = create_spend_proof(
  82. spend_pk,
  83. input.note.value,
  84. input.note.token_id,
  85. input.note.value_blind,
  86. token_blind,
  87. input.note.serial,
  88. input.note.coin_blind,
  89. input.secret,
  90. input.leaf_position,
  91. input.merkle_path,
  92. signature_secret,
  93. )?;
  94. // First we make the tx then sign after
  95. signature_secrets.push(signature_secret);
  96. let input = PartialTransactionInput { spend_proof: proof, revealed };
  97. inputs.push(input);
  98. }
  99. let mut outputs = vec![];
  100. let mut output_blinds = vec![];
  101. for (i, output) in self.outputs.iter().enumerate() {
  102. let value_blind = if i == self.outputs.len() - 1 {
  103. Self::compute_remainder_blind(&clear_inputs, &input_blinds, &output_blinds)
  104. } else {
  105. DrkValueBlind::random(&mut OsRng)
  106. };
  107. output_blinds.push(value_blind);
  108. let serial = DrkSerial::random(&mut OsRng);
  109. let coin_blind = DrkCoinBlind::random(&mut OsRng);
  110. let (mint_proof, revealed) = create_mint_proof(
  111. mint_pk,
  112. output.value,
  113. output.token_id,
  114. value_blind,
  115. token_blind,
  116. serial,
  117. coin_blind,
  118. output.public,
  119. )?;
  120. // Encrypted note
  121. let note = Note {
  122. serial,
  123. value: output.value,
  124. token_id: output.token_id,
  125. coin_blind,
  126. value_blind,
  127. };
  128. let encrypted_note = note.encrypt(&output.public)?;
  129. let output = TransactionOutput { mint_proof, revealed, enc_note: encrypted_note };
  130. outputs.push(output);
  131. }
  132. let partial_tx = PartialTransaction { clear_inputs, inputs, outputs };
  133. let mut unsigned_tx_data = vec![];
  134. partial_tx.encode(&mut unsigned_tx_data)?;
  135. let mut clear_inputs = vec![];
  136. for (input, info) in partial_tx.clear_inputs.into_iter().zip(self.clear_inputs) {
  137. let secret = info.signature_secret;
  138. let signature = secret.sign(&unsigned_tx_data[..]);
  139. let input = TransactionClearInput::from_partial(input, signature);
  140. clear_inputs.push(input);
  141. }
  142. let mut inputs = vec![];
  143. for (input, signature_secret) in
  144. partial_tx.inputs.into_iter().zip(signature_secrets.into_iter())
  145. {
  146. let signature = signature_secret.sign(&unsigned_tx_data[..]);
  147. let input = TransactionInput::from_partial(input, signature);
  148. inputs.push(input);
  149. }
  150. Ok(Transaction { clear_inputs, inputs, outputs: partial_tx.outputs })
  151. }
  152. }