validate.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. use darkfi::{
  2. crypto::{
  3. keypair::PublicKey, merkle_node::MerkleNode, nullifier::Nullifier, schnorr,
  4. schnorr::SchnorrPublic, types::DrkCircuitField, Proof,
  5. },
  6. util::serial::{Encodable, SerialDecodable, SerialEncodable, VarInt},
  7. Error as DarkFiError,
  8. };
  9. use log::{debug, error};
  10. use pasta_curves::{
  11. arithmetic::CurveAffine,
  12. group::{ff::Field, Curve, Group},
  13. pallas,
  14. };
  15. use std::any::{Any, TypeId};
  16. use crate::{
  17. dao_contract::{DaoBulla, State as DaoState},
  18. demo::{CallDataBase, StateRegistry, Transaction},
  19. money_contract::state::State as MoneyState,
  20. note::EncryptedNote2,
  21. };
  22. #[derive(Debug, Clone, thiserror::Error)]
  23. pub enum Error {
  24. #[error("Invalid proposal")]
  25. InvalidProposal,
  26. #[error("Voting with already spent coinage")]
  27. SpentCoin,
  28. #[error("Double voting")]
  29. DoubleVote,
  30. #[error("Invalid input merkle root")]
  31. InvalidInputMerkleRoot,
  32. #[error("Invalid DAO merkle root")]
  33. InvalidDaoMerkleRoot,
  34. #[error("Signature verification failed")]
  35. SignatureVerifyFailed,
  36. #[error("DarkFi error: {0}")]
  37. DarkFiError(String),
  38. }
  39. type Result<T> = std::result::Result<T, Error>;
  40. impl From<DarkFiError> for Error {
  41. fn from(err: DarkFiError) -> Self {
  42. Self::DarkFiError(err.to_string())
  43. }
  44. }
  45. pub struct CallData {
  46. pub header: Header,
  47. pub inputs: Vec<Input>,
  48. pub signatures: Vec<schnorr::Signature>,
  49. }
  50. impl CallDataBase for CallData {
  51. fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)> {
  52. let mut zk_publics = Vec::new();
  53. let mut total_value_commit = pallas::Point::identity();
  54. assert!(self.inputs.len() > 0, "inputs length cannot be zero");
  55. for input in &self.inputs {
  56. total_value_commit += input.value_commit;
  57. let value_coords = input.value_commit.to_affine().coordinates().unwrap();
  58. let value_commit_x = *value_coords.x();
  59. let value_commit_y = *value_coords.y();
  60. let sigpub_coords = input.signature_public.0.to_affine().coordinates().unwrap();
  61. let sigpub_x = *sigpub_coords.x();
  62. let sigpub_y = *sigpub_coords.y();
  63. zk_publics.push((
  64. "dao-vote-burn".to_string(),
  65. vec![
  66. input.nullifier.0,
  67. value_commit_x,
  68. value_commit_y,
  69. self.header.token_commit,
  70. input.merkle_root.0,
  71. sigpub_x,
  72. sigpub_y,
  73. ],
  74. ));
  75. }
  76. let vote_commit_coords = self.header.vote_commit.to_affine().coordinates().unwrap();
  77. let vote_commit_x = *vote_commit_coords.x();
  78. let vote_commit_y = *vote_commit_coords.y();
  79. let value_commit_coords = total_value_commit.to_affine().coordinates().unwrap();
  80. let value_commit_x = *value_commit_coords.x();
  81. let value_commit_y = *value_commit_coords.y();
  82. zk_publics.push((
  83. "dao-vote-main".to_string(),
  84. vec![
  85. self.header.token_commit,
  86. self.header.proposal_bulla,
  87. vote_commit_x,
  88. vote_commit_y,
  89. value_commit_x,
  90. value_commit_y,
  91. ],
  92. ));
  93. zk_publics
  94. }
  95. fn as_any(&self) -> &dyn Any {
  96. self
  97. }
  98. }
  99. #[derive(Clone, SerialEncodable, SerialDecodable)]
  100. pub struct Header {
  101. pub token_commit: pallas::Base,
  102. pub proposal_bulla: pallas::Base,
  103. pub vote_commit: pallas::Point,
  104. pub enc_note: EncryptedNote2,
  105. }
  106. #[derive(Clone, SerialEncodable, SerialDecodable)]
  107. pub struct Input {
  108. pub nullifier: Nullifier,
  109. pub value_commit: pallas::Point,
  110. pub merkle_root: MerkleNode,
  111. pub signature_public: PublicKey,
  112. }
  113. pub fn state_transition(
  114. states: &StateRegistry,
  115. func_call_index: usize,
  116. parent_tx: &Transaction,
  117. ) -> Result<Update> {
  118. let func_call = &parent_tx.func_calls[func_call_index];
  119. let call_data = func_call.call_data.as_any();
  120. assert_eq!((&*call_data).type_id(), TypeId::of::<CallData>());
  121. let call_data = call_data.downcast_ref::<CallData>();
  122. // This will be inside wasm so unwrap is fine.
  123. let call_data = call_data.unwrap();
  124. let dao_state = states.lookup::<DaoState>(&"DAO".to_string()).unwrap();
  125. // Check proposal_bulla exists
  126. let votes_info = dao_state.lookup_proposal_votes(call_data.header.proposal_bulla);
  127. if votes_info.is_none() {
  128. return Err(Error::InvalidProposal)
  129. }
  130. let votes_info = votes_info.unwrap();
  131. // Check the merkle roots for the input coins are valid
  132. let mut vote_nulls = Vec::new();
  133. let mut total_value_commit = pallas::Point::identity();
  134. for input in &call_data.inputs {
  135. let money_state = states.lookup::<MoneyState>(&"Money".to_string()).unwrap();
  136. if !money_state.is_valid_merkle(&input.merkle_root) {
  137. return Err(Error::InvalidInputMerkleRoot)
  138. }
  139. if money_state.nullifier_exists(&input.nullifier) {
  140. return Err(Error::SpentCoin)
  141. }
  142. if votes_info.nullifier_exists(&input.nullifier) {
  143. return Err(Error::DoubleVote)
  144. }
  145. total_value_commit += input.value_commit;
  146. vote_nulls.push(input.nullifier);
  147. }
  148. // Verify the available signatures
  149. let mut unsigned_tx_data = vec![];
  150. call_data.header.encode(&mut unsigned_tx_data).expect("failed to encode data");
  151. call_data.inputs.encode(&mut unsigned_tx_data).expect("failed to encode inputs");
  152. func_call.proofs.encode(&mut unsigned_tx_data).expect("failed to encode proofs");
  153. //debug!("unsigned_tx_data: {:?}", unsigned_tx_data);
  154. for (i, (input, signature)) in
  155. call_data.inputs.iter().zip(call_data.signatures.iter()).enumerate()
  156. {
  157. let public = &input.signature_public;
  158. if !public.verify(&unsigned_tx_data[..], signature) {
  159. return Err(Error::SignatureVerifyFailed)
  160. }
  161. }
  162. Ok(Update {
  163. proposal_bulla: call_data.header.proposal_bulla,
  164. vote_nulls,
  165. vote_commit: call_data.header.vote_commit,
  166. value_commit: total_value_commit,
  167. })
  168. }
  169. #[derive(Clone)]
  170. pub struct Update {
  171. proposal_bulla: pallas::Base,
  172. vote_nulls: Vec<Nullifier>,
  173. pub vote_commit: pallas::Point,
  174. pub value_commit: pallas::Point,
  175. }
  176. pub fn apply(states: &mut StateRegistry, mut update: Update) {
  177. let state = states.lookup_mut::<DaoState>(&"DAO".to_string()).unwrap();
  178. let votes_info = state.lookup_proposal_votes_mut(update.proposal_bulla).unwrap();
  179. votes_info.vote_commits += update.vote_commit;
  180. votes_info.value_commits += update.value_commit;
  181. votes_info.vote_nulls.append(&mut update.vote_nulls);
  182. }