validate.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. use std::any::{Any, TypeId};
  2. use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
  3. use incrementalmerkletree::Tree;
  4. use log::{debug, error};
  5. use pasta_curves::{group::Group, pallas};
  6. use darkfi::{
  7. crypto::{
  8. coin::Coin,
  9. keypair::PublicKey,
  10. merkle_node::MerkleNode,
  11. nullifier::Nullifier,
  12. types::{DrkCircuitField, DrkTokenId, DrkValueBlind, DrkValueCommit},
  13. util::{pedersen_commitment_base, pedersen_commitment_u64},
  14. BurnRevealedValues, MintRevealedValues,
  15. },
  16. Error as DarkFiError,
  17. };
  18. use crate::{
  19. contract::{
  20. dao_contract,
  21. money_contract::{state::State, CONTRACT_ID},
  22. },
  23. note::EncryptedNote2,
  24. util::{CallDataBase, StateRegistry, Transaction, UpdateBase},
  25. };
  26. const TARGET: &str = "money_contract::transfer::validate::state_transition()";
  27. /// A struct representing a state update.
  28. /// This gets applied on top of an existing state.
  29. #[derive(Clone)]
  30. pub struct Update {
  31. /// All nullifiers in a transaction
  32. pub nullifiers: Vec<Nullifier>,
  33. /// All coins in a transaction
  34. pub coins: Vec<Coin>,
  35. /// All encrypted notes in a transaction
  36. pub enc_notes: Vec<EncryptedNote2>,
  37. }
  38. impl UpdateBase for Update {
  39. fn apply(mut self: Box<Self>, states: &mut StateRegistry) {
  40. let state = states.lookup_mut::<State>(*CONTRACT_ID).unwrap();
  41. // Extend our list of nullifiers with the ones from the update
  42. state.nullifiers.append(&mut self.nullifiers);
  43. //// Update merkle tree and witnesses
  44. for (coin, enc_note) in self.coins.into_iter().zip(self.enc_notes.into_iter()) {
  45. // Add the new coins to the Merkle tree
  46. let node = MerkleNode(coin.0);
  47. state.tree.append(&node);
  48. // Keep track of all Merkle roots that have existed
  49. state.merkle_roots.push(state.tree.root(0).unwrap());
  50. state.wallet_cache.try_decrypt_note(coin, enc_note, &mut state.tree);
  51. }
  52. }
  53. }
  54. pub fn state_transition(
  55. states: &StateRegistry,
  56. func_call_index: usize,
  57. parent_tx: &Transaction,
  58. ) -> Result<Box<dyn UpdateBase + Send>> {
  59. // Check the public keys in the clear inputs to see if they're coming
  60. // from a valid cashier or faucet.
  61. debug!(target: TARGET, "Iterate clear_inputs");
  62. let func_call = &parent_tx.func_calls[func_call_index];
  63. let call_data = func_call.call_data.as_any();
  64. assert_eq!((*call_data).type_id(), TypeId::of::<CallData>());
  65. let call_data = call_data.downcast_ref::<CallData>();
  66. // This will be inside wasm so unwrap is fine.
  67. let call_data = call_data.unwrap();
  68. let state = states.lookup::<State>(*CONTRACT_ID).expect("Return type is not of type State");
  69. // Code goes here
  70. for (i, input) in call_data.clear_inputs.iter().enumerate() {
  71. let pk = &input.signature_public;
  72. // TODO: this depends on the token ID
  73. if !state.is_valid_cashier_public_key(pk) && !state.is_valid_faucet_public_key(pk) {
  74. error!(target: TARGET, "Invalid pubkey for clear input: {:?}", pk);
  75. return Err(Error::VerifyFailed(VerifyFailed::InvalidCashierOrFaucetKey(i)))
  76. }
  77. }
  78. // Nullifiers in the transaction
  79. let mut nullifiers = Vec::with_capacity(call_data.inputs.len());
  80. debug!(target: TARGET, "Iterate inputs");
  81. for (i, input) in call_data.inputs.iter().enumerate() {
  82. let merkle = &input.revealed.merkle_root;
  83. // The Merkle root is used to know whether this is a coin that
  84. // existed in a previous state.
  85. if !state.is_valid_merkle(merkle) {
  86. error!(target: TARGET, "Invalid Merkle root (input {})", i);
  87. debug!(target: TARGET, "root: {:?}", merkle);
  88. return Err(Error::VerifyFailed(VerifyFailed::InvalidMerkle(i)))
  89. }
  90. // Check the spend_hook is satisfied
  91. // The spend_hook says a coin must invoke another contract function when being spent
  92. // If the value is set, then we check the function call exists
  93. let spend_hook = &input.revealed.spend_hook;
  94. if spend_hook != &pallas::Base::from(0) {
  95. // spend_hook is set so we enforce the rules
  96. let mut is_found = false;
  97. for (i, func_call) in parent_tx.func_calls.iter().enumerate() {
  98. // Skip current func_call
  99. if i == func_call_index {
  100. continue
  101. }
  102. // TODO: we need to change these to pallas::Base
  103. // temporary workaround for now
  104. // if func_call.func_id == spend_hook ...
  105. if func_call.func_id == *dao_contract::exec::FUNC_ID {
  106. is_found = true;
  107. break
  108. }
  109. }
  110. if !is_found {
  111. return Err(Error::VerifyFailed(VerifyFailed::SpendHookNotSatisfied))
  112. }
  113. }
  114. // The nullifiers should not already exist.
  115. // It is the double-spend protection.
  116. let nullifier = &input.revealed.nullifier;
  117. if state.nullifier_exists(nullifier) ||
  118. (1..nullifiers.len()).any(|i| nullifiers[i..].contains(&nullifiers[i - 1]))
  119. {
  120. error!(target: TARGET, "Duplicate nullifier found (input {})", i);
  121. debug!(target: TARGET, "nullifier: {:?}", nullifier);
  122. return Err(Error::VerifyFailed(VerifyFailed::NullifierExists(i)))
  123. }
  124. nullifiers.push(input.revealed.nullifier);
  125. }
  126. debug!(target: TARGET, "Verifying call data");
  127. match call_data.verify() {
  128. Ok(()) => {
  129. debug!(target: TARGET, "Verified successfully")
  130. }
  131. Err(e) => {
  132. error!(target: TARGET, "Failed verifying zk proofs: {}", e);
  133. return Err(Error::VerifyFailed(VerifyFailed::ProofVerifyFailed(e.to_string())))
  134. }
  135. }
  136. // Newly created coins for this transaction
  137. let mut coins = Vec::with_capacity(call_data.outputs.len());
  138. let mut enc_notes = Vec::with_capacity(call_data.outputs.len());
  139. for output in &call_data.outputs {
  140. // Gather all the coins
  141. coins.push(output.revealed.coin);
  142. enc_notes.push(output.enc_note.clone());
  143. }
  144. Ok(Box::new(Update { nullifiers, coins, enc_notes }))
  145. }
  146. /// A DarkFi transaction
  147. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  148. pub struct CallData {
  149. /// Clear inputs
  150. pub clear_inputs: Vec<ClearInput>,
  151. /// Anonymous inputs
  152. pub inputs: Vec<Input>,
  153. /// Anonymous outputs
  154. pub outputs: Vec<Output>,
  155. }
  156. impl CallDataBase for CallData {
  157. fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)> {
  158. let mut public_values = Vec::new();
  159. for input in &self.inputs {
  160. public_values.push(("money-transfer-burn".to_string(), input.revealed.make_outputs()));
  161. }
  162. for output in &self.outputs {
  163. public_values.push(("money-transfer-mint".to_string(), output.revealed.make_outputs()));
  164. }
  165. public_values
  166. }
  167. fn as_any(&self) -> &dyn Any {
  168. self
  169. }
  170. fn signature_public_keys(&self) -> Vec<PublicKey> {
  171. let mut signature_public_keys = Vec::new();
  172. for input in self.clear_inputs.clone() {
  173. signature_public_keys.push(input.signature_public);
  174. }
  175. signature_public_keys
  176. }
  177. fn encode_bytes(
  178. &self,
  179. mut writer: &mut dyn std::io::Write,
  180. ) -> core::result::Result<usize, std::io::Error> {
  181. self.encode(&mut writer)
  182. }
  183. }
  184. impl CallData {
  185. /// Verify the transaction
  186. pub fn verify(&self) -> VerifyResult<()> {
  187. // must have minimum 1 clear or anon input, and 1 output
  188. if self.clear_inputs.len() + self.inputs.len() == 0 {
  189. error!("tx::verify(): Missing inputs");
  190. return Err(VerifyFailed::LackingInputs)
  191. }
  192. if self.outputs.is_empty() {
  193. error!("tx::verify(): Missing outputs");
  194. return Err(VerifyFailed::LackingOutputs)
  195. }
  196. // Accumulator for the value commitments
  197. let mut valcom_total = DrkValueCommit::identity();
  198. // Add values from the clear inputs
  199. for input in &self.clear_inputs {
  200. valcom_total += pedersen_commitment_u64(input.value, input.value_blind);
  201. }
  202. // Add values from the inputs
  203. for input in &self.inputs {
  204. valcom_total += &input.revealed.value_commit;
  205. }
  206. // Subtract values from the outputs
  207. for output in &self.outputs {
  208. valcom_total -= &output.revealed.value_commit;
  209. }
  210. // If the accumulator is not back in its initial state,
  211. // there's a value mismatch.
  212. if valcom_total != DrkValueCommit::identity() {
  213. error!("tx::verify(): Missing funds");
  214. return Err(VerifyFailed::MissingFunds)
  215. }
  216. // Verify that the token commitments match
  217. if !self.verify_token_commitments() {
  218. error!("tx::verify(): Token ID mismatch");
  219. return Err(VerifyFailed::TokenMismatch)
  220. }
  221. Ok(())
  222. }
  223. fn verify_token_commitments(&self) -> bool {
  224. assert_ne!(self.outputs.len(), 0);
  225. let token_commit_value = self.outputs[0].revealed.token_commit;
  226. let mut failed =
  227. self.inputs.iter().any(|input| input.revealed.token_commit != token_commit_value);
  228. failed = failed ||
  229. self.outputs.iter().any(|output| output.revealed.token_commit != token_commit_value);
  230. failed = failed ||
  231. self.clear_inputs.iter().any(|input| {
  232. pedersen_commitment_base(input.token_id, input.token_blind) != token_commit_value
  233. });
  234. !failed
  235. }
  236. }
  237. /// A transaction's clear input
  238. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  239. pub struct ClearInput {
  240. /// Input's value (amount)
  241. pub value: u64,
  242. /// Input's token ID
  243. pub token_id: DrkTokenId,
  244. /// Blinding factor for `value`
  245. pub value_blind: DrkValueBlind,
  246. /// Blinding factor for `token_id`
  247. pub token_blind: DrkValueBlind,
  248. /// Public key for the signature
  249. pub signature_public: PublicKey,
  250. }
  251. /// A transaction's anonymous input
  252. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  253. pub struct Input {
  254. /// Public inputs for the zero-knowledge proof
  255. pub revealed: BurnRevealedValues,
  256. }
  257. /// A transaction's anonymous output
  258. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  259. pub struct Output {
  260. /// Public inputs for the zero-knowledge proof
  261. pub revealed: MintRevealedValues,
  262. /// The encrypted note
  263. pub enc_note: EncryptedNote2,
  264. }
  265. #[derive(Debug, Clone, thiserror::Error)]
  266. pub enum Error {
  267. #[error(transparent)]
  268. VerifyFailed(#[from] VerifyFailed),
  269. #[error("DarkFi error: {0}")]
  270. DarkFiError(String),
  271. }
  272. /// Transaction verification errors
  273. #[derive(Debug, Clone, thiserror::Error)]
  274. pub enum VerifyFailed {
  275. #[error("Transaction has no inputs")]
  276. LackingInputs,
  277. #[error("Transaction has no outputs")]
  278. LackingOutputs,
  279. #[error("Invalid cashier/faucet public key for clear input {0}")]
  280. InvalidCashierOrFaucetKey(usize),
  281. #[error("Invalid Merkle root for input {0}")]
  282. InvalidMerkle(usize),
  283. #[error("Spend hook invoking function is not attached")]
  284. SpendHookNotSatisfied,
  285. #[error("Nullifier already exists for input {0}")]
  286. NullifierExists(usize),
  287. #[error("Token commitments in inputs or outputs to not match")]
  288. TokenMismatch,
  289. #[error("Money in does not match money out (value commitments)")]
  290. MissingFunds,
  291. #[error("Failed verifying zk proofs: {0}")]
  292. ProofVerifyFailed(String),
  293. #[error("Internal error: {0}")]
  294. InternalError(String),
  295. #[error("DarkFi error: {0}")]
  296. DarkFiError(String),
  297. }
  298. type Result<T> = std::result::Result<T, Error>;
  299. impl From<Error> for VerifyFailed {
  300. fn from(err: Error) -> Self {
  301. Self::InternalError(err.to_string())
  302. }
  303. }
  304. impl From<DarkFiError> for VerifyFailed {
  305. fn from(err: DarkFiError) -> Self {
  306. Self::DarkFiError(err.to_string())
  307. }
  308. }
  309. impl From<DarkFiError> for Error {
  310. fn from(err: DarkFiError) -> Self {
  311. Self::DarkFiError(err.to_string())
  312. }
  313. }
  314. /// Result type used in transaction verifications
  315. pub type VerifyResult<T> = std::result::Result<T, VerifyFailed>;