mod.rs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. use std::io;
  2. use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable, VarInt};
  3. use log::error;
  4. use pasta_curves::group::Group;
  5. use crate::{
  6. crypto::{
  7. burn_proof::verify_burn_proof,
  8. keypair::PublicKey,
  9. mint_proof::verify_mint_proof,
  10. note::EncryptedNote,
  11. proof::VerifyingKey,
  12. schnorr,
  13. schnorr::SchnorrPublic,
  14. types::{DrkTokenId, DrkValueBlind, DrkValueCommit},
  15. util::{pedersen_commitment_base, pedersen_commitment_u64},
  16. BurnRevealedValues, MintRevealedValues, Proof,
  17. },
  18. Result, VerifyFailed, VerifyResult,
  19. };
  20. pub mod builder;
  21. pub mod partial;
  22. /// A DarkFi transaction
  23. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  24. pub struct Transaction {
  25. /// Clear inputs
  26. pub clear_inputs: Vec<TransactionClearInput>,
  27. /// Anonymous inputs
  28. pub inputs: Vec<TransactionInput>,
  29. /// Anonymous outputs
  30. pub outputs: Vec<TransactionOutput>,
  31. }
  32. /// A transaction's clear input
  33. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  34. pub struct TransactionClearInput {
  35. /// Input's value (amount)
  36. pub value: u64,
  37. /// Input's token ID
  38. pub token_id: DrkTokenId,
  39. /// Blinding factor for `value`
  40. pub value_blind: DrkValueBlind,
  41. /// Blinding factor for `token_id`
  42. pub token_blind: DrkValueBlind,
  43. /// Public key for the signature
  44. pub signature_public: PublicKey,
  45. /// Transaction signature
  46. pub signature: schnorr::Signature,
  47. }
  48. /// A transaction's anonymous input
  49. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  50. pub struct TransactionInput {
  51. /// Zero-knowledge proof for the input
  52. pub burn_proof: Proof,
  53. /// Public inputs for the zero-knowledge proof
  54. pub revealed: BurnRevealedValues,
  55. /// Input's signature
  56. pub signature: schnorr::Signature,
  57. }
  58. /// A transaction's anonymous output
  59. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  60. pub struct TransactionOutput {
  61. /// Zero-knowledge proof for the output
  62. pub mint_proof: Proof,
  63. /// Public inputs for the zero-knowledge proof
  64. pub revealed: MintRevealedValues,
  65. /// The encrypted note
  66. pub enc_note: EncryptedNote,
  67. }
  68. impl Transaction {
  69. /// Verify the transaction
  70. pub fn verify(&self, mint_vk: &VerifyingKey, burn_vk: &VerifyingKey) -> VerifyResult<()> {
  71. // Transaction must have minimum 1 clear or anon input, and 1 output
  72. if self.clear_inputs.len() + self.inputs.len() == 0 {
  73. error!("tx::verify(): Missing inputs");
  74. return Err(VerifyFailed::LackingInputs)
  75. }
  76. if self.outputs.is_empty() {
  77. error!("tx::verify(): Missing outputs");
  78. return Err(VerifyFailed::LackingOutputs)
  79. }
  80. // Accumulator for the value commitments
  81. let mut valcom_total = DrkValueCommit::identity();
  82. // Add values from the clear inputs
  83. for input in &self.clear_inputs {
  84. valcom_total += pedersen_commitment_u64(input.value, input.value_blind);
  85. }
  86. // Add values from the inputs
  87. for (i, input) in self.inputs.iter().enumerate() {
  88. match verify_burn_proof(burn_vk, &input.burn_proof, &input.revealed) {
  89. Ok(()) => valcom_total += &input.revealed.value_commit,
  90. Err(e) => {
  91. error!("tx::verify(): Failed to verify burn proof {}: {}", i, e);
  92. return Err(VerifyFailed::BurnProof(i))
  93. }
  94. }
  95. }
  96. // Subtract values from the outputs
  97. for (i, output) in self.outputs.iter().enumerate() {
  98. match verify_mint_proof(mint_vk, &output.mint_proof, &output.revealed) {
  99. Ok(()) => valcom_total -= &output.revealed.value_commit,
  100. Err(e) => {
  101. error!("tx::verify(): Failed to verify mint proof {}: {}", i, e);
  102. return Err(VerifyFailed::MintProof(i))
  103. }
  104. }
  105. }
  106. // If the accumulator is not back in its initial state,
  107. // there's a value mismatch.
  108. if valcom_total != DrkValueCommit::identity() {
  109. error!("tx::verify(): Missing funds");
  110. return Err(VerifyFailed::MissingFunds)
  111. }
  112. // Verify that the token commitments match
  113. if !self.verify_token_commitments() {
  114. error!("tx::verify(): Token ID mismatch");
  115. return Err(VerifyFailed::TokenMismatch)
  116. }
  117. // Verify the available signatures
  118. let mut unsigned_tx_data = vec![];
  119. self.encode_without_signature(&mut unsigned_tx_data)?;
  120. for (i, input) in self.clear_inputs.iter().enumerate() {
  121. let public = &input.signature_public;
  122. if !public.verify(&unsigned_tx_data[..], &input.signature) {
  123. error!("tx::verify(): Failed to verify Clear Input signature {}", i);
  124. return Err(VerifyFailed::ClearInputSignature(i))
  125. }
  126. }
  127. for (i, input) in self.inputs.iter().enumerate() {
  128. let public = &input.revealed.signature_public;
  129. if !public.verify(&unsigned_tx_data[..], &input.signature) {
  130. error!("tx::verify(): Failed to verify Input signature {}", i);
  131. return Err(VerifyFailed::InputSignature(i))
  132. }
  133. }
  134. Ok(())
  135. }
  136. pub fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
  137. let mut len = 0;
  138. len += self.clear_inputs.encode_without_signature(&mut s)?;
  139. len += self.inputs.encode_without_signature(&mut s)?;
  140. len += self.outputs.encode(s)?;
  141. Ok(len)
  142. }
  143. fn verify_token_commitments(&self) -> bool {
  144. assert_ne!(self.outputs.len(), 0);
  145. let token_commit_value = self.outputs[0].revealed.token_commit;
  146. let mut failed =
  147. self.inputs.iter().any(|input| input.revealed.token_commit != token_commit_value);
  148. failed = failed ||
  149. self.outputs.iter().any(|output| output.revealed.token_commit != token_commit_value);
  150. failed = failed ||
  151. self.clear_inputs.iter().any(|input| {
  152. pedersen_commitment_base(input.token_id, input.token_blind) != token_commit_value
  153. });
  154. !failed
  155. }
  156. }
  157. impl TransactionClearInput {
  158. fn from_partial(
  159. partial: partial::PartialTransactionClearInput,
  160. signature: schnorr::Signature,
  161. ) -> Self {
  162. Self {
  163. value: partial.value,
  164. token_id: partial.token_id,
  165. value_blind: partial.value_blind,
  166. token_blind: partial.token_blind,
  167. signature_public: partial.signature_public,
  168. signature,
  169. }
  170. }
  171. fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
  172. let mut len = 0;
  173. len += self.value.encode(&mut s)?;
  174. len += self.token_id.encode(&mut s)?;
  175. len += self.value_blind.encode(&mut s)?;
  176. len += self.token_blind.encode(&mut s)?;
  177. len += self.signature_public.encode(s)?;
  178. Ok(len)
  179. }
  180. }
  181. impl TransactionInput {
  182. pub fn from_partial(
  183. partial: partial::PartialTransactionInput,
  184. signature: schnorr::Signature,
  185. ) -> Self {
  186. Self { burn_proof: partial.burn_proof, revealed: partial.revealed, signature }
  187. }
  188. fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
  189. let mut len = 0;
  190. len += self.burn_proof.encode(&mut s)?;
  191. len += self.revealed.encode(&mut s)?;
  192. Ok(len)
  193. }
  194. }
  195. trait EncodableWithoutSignature {
  196. fn encode_without_signature<S: io::Write>(&self, s: S) -> Result<usize>;
  197. }
  198. macro_rules! impl_vec_without_signature {
  199. ($type: ty) => {
  200. impl EncodableWithoutSignature for Vec<$type> {
  201. #[inline]
  202. fn encode_without_signature<S: io::Write>(&self, mut s: S) -> Result<usize> {
  203. let mut len = 0;
  204. len += VarInt(self.len() as u64).encode(&mut s)?;
  205. for c in self.iter() {
  206. len += c.encode_without_signature(&mut s)?;
  207. }
  208. Ok(len)
  209. }
  210. }
  211. };
  212. }
  213. impl_vec_without_signature!(TransactionClearInput);
  214. impl_vec_without_signature!(TransactionInput);