builder.rs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. use bellman::groth16;
  2. use bls12_381::Bls12;
  3. use ff::Field;
  4. use rand::rngs::OsRng;
  5. use super::{
  6. partial::{PartialTransaction, PartialTransactionClearInput, PartialTransactionInput},
  7. Transaction, TransactionClearInput, TransactionInput, TransactionOutput,
  8. };
  9. use crate::crypto::{
  10. create_mint_proof, create_spend_proof, merkle::MerklePath, merkle_node::MerkleNode, note::Note,
  11. schnorr,
  12. };
  13. use crate::serial::Encodable;
  14. pub struct TransactionBuilder {
  15. pub clear_inputs: Vec<TransactionBuilderClearInputInfo>,
  16. pub inputs: Vec<TransactionBuilderInputInfo>,
  17. pub outputs: Vec<TransactionBuilderOutputInfo>,
  18. }
  19. pub struct TransactionBuilderClearInputInfo {
  20. pub value: u64,
  21. pub token_id: jubjub::Fr,
  22. pub signature_secret: jubjub::Fr,
  23. }
  24. pub struct TransactionBuilderInputInfo {
  25. pub merkle_path: MerklePath<MerkleNode>,
  26. pub secret: jubjub::Fr,
  27. pub note: Note,
  28. }
  29. pub struct TransactionBuilderOutputInfo {
  30. pub value: u64,
  31. pub token_id: jubjub::Fr,
  32. pub public: jubjub::SubgroupPoint,
  33. }
  34. impl TransactionBuilder {
  35. fn compute_remainder_blind(
  36. clear_inputs: &[PartialTransactionClearInput],
  37. input_blinds: &[jubjub::Fr],
  38. output_blinds: &[jubjub::Fr],
  39. ) -> jubjub::Fr {
  40. let mut total = jubjub::Fr::zero();
  41. for input in clear_inputs {
  42. total += input.valcom_blind;
  43. }
  44. for input_blind in input_blinds {
  45. total += input_blind;
  46. }
  47. for output_blind in output_blinds {
  48. total -= output_blind;
  49. }
  50. total
  51. }
  52. pub fn build(
  53. self,
  54. mint_params: &groth16::Parameters<Bls12>,
  55. spend_params: &groth16::Parameters<Bls12>,
  56. ) -> Transaction {
  57. let mut clear_inputs = vec![];
  58. let token_commit_blind: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  59. for input in &self.clear_inputs {
  60. let signature_public =
  61. zcash_primitives::constants::SPENDING_KEY_GENERATOR * input.signature_secret;
  62. let valcom_blind: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  63. let clear_input = PartialTransactionClearInput {
  64. value: input.value,
  65. token_id: input.token_id,
  66. valcom_blind,
  67. token_commit_blind,
  68. signature_public,
  69. };
  70. clear_inputs.push(clear_input);
  71. }
  72. let mut inputs = vec![];
  73. let mut input_blinds = vec![];
  74. let mut signature_secrets = vec![];
  75. for input in &self.inputs {
  76. input_blinds.push(input.note.valcom_blind);
  77. let signature_secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  78. // make proof
  79. // TODO: Some stupid glue code. Need to sort this out
  80. let auth_path: Vec<(bls12_381::Scalar, bool)> = input
  81. .merkle_path
  82. .auth_path
  83. .iter()
  84. .map(|(node, b)| ((*node).into(), *b))
  85. .collect();
  86. let (proof, revealed) = create_spend_proof(
  87. &spend_params,
  88. input.note.value,
  89. input.note.token_id,
  90. input.note.valcom_blind,
  91. token_commit_blind,
  92. input.note.serial,
  93. input.note.coin_blind,
  94. input.secret,
  95. auth_path,
  96. signature_secret,
  97. );
  98. // First we make the tx then sign after
  99. let signature_secret = schnorr::SecretKey(signature_secret);
  100. signature_secrets.push(signature_secret);
  101. let input = PartialTransactionInput {
  102. spend_proof: proof,
  103. revealed,
  104. };
  105. inputs.push(input);
  106. }
  107. let mut outputs = vec![];
  108. let mut output_blinds = vec![];
  109. for (i, output) in self.outputs.iter().enumerate() {
  110. let valcom_blind = if i == self.outputs.len() - 1 {
  111. Self::compute_remainder_blind(&clear_inputs, &input_blinds, &output_blinds)
  112. } else {
  113. jubjub::Fr::random(&mut OsRng)
  114. };
  115. output_blinds.push(valcom_blind);
  116. let serial: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  117. let coin_blind: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  118. let (mint_proof, revealed) = create_mint_proof(
  119. mint_params,
  120. output.value,
  121. output.token_id,
  122. valcom_blind,
  123. token_commit_blind,
  124. serial,
  125. coin_blind,
  126. output.public,
  127. );
  128. // Encrypted note
  129. let note = Note {
  130. serial,
  131. value: output.value,
  132. token_id: output.token_id,
  133. coin_blind,
  134. valcom_blind,
  135. };
  136. let encrypted_note = note.encrypt(&output.public).unwrap();
  137. let output = TransactionOutput {
  138. mint_proof,
  139. revealed,
  140. enc_note: encrypted_note,
  141. };
  142. outputs.push(output);
  143. }
  144. let partial_tx = PartialTransaction {
  145. clear_inputs,
  146. inputs,
  147. outputs,
  148. };
  149. let mut unsigned_tx_data = vec![];
  150. partial_tx
  151. .encode(&mut unsigned_tx_data)
  152. .expect("TODO handle this");
  153. let mut clear_inputs = vec![];
  154. for (input, info) in partial_tx.clear_inputs.into_iter().zip(self.clear_inputs) {
  155. let secret = schnorr::SecretKey(info.signature_secret);
  156. let signature = secret.sign(&unsigned_tx_data[..]);
  157. let input = TransactionClearInput::from_partial(input, signature);
  158. clear_inputs.push(input);
  159. }
  160. let mut inputs = vec![];
  161. for (input, signature_secret) in partial_tx
  162. .inputs
  163. .into_iter()
  164. .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. Transaction {
  171. clear_inputs,
  172. inputs,
  173. outputs: partial_tx.outputs,
  174. }
  175. }
  176. }