Przeglądaj źródła

create proposals is working

narodnik 4 lat temu
rodzic
commit
51c2007762

+ 3 - 1
bin/daod/proof/dao-propose-burn.zk

@@ -7,6 +7,8 @@ constant "DaoProposeInput" {
 contract "DaoProposeInput" {
 	Base secret,
 	Base serial,
+	Base spend_hook,
+	Base user_data,
 	Base value,
 	Base token,
 	Base coin_blind,
@@ -41,7 +43,7 @@ circuit "DaoProposeInput" {
 	pub = ec_mul_base(secret, NULLIFIER_K);
 	pub_x = ec_get_x(pub);
 	pub_y = ec_get_y(pub);
-	C = poseidon_hash(pub_x, pub_y, value, token, serial, coin_blind);
+	C = poseidon_hash(pub_x, pub_y, value, token, serial, spend_hook, user_data, coin_blind);
 
 	# Merkle root
 	root = calculate_merkle_root(leaf_pos, path, C);

+ 18 - 4
bin/daod/src/dao_contract/propose/validate.rs

@@ -13,15 +13,20 @@ use darkfi::{
 use log::{debug, error};
 use pasta_curves::{
     arithmetic::CurveAffine,
-    group::{ff::Field, Curve},
+    group::{ff::Field, Curve, Group},
     pallas,
 };
 use std::any::{Any, TypeId};
 
+use crate::money_contract::state::State as MoneyState;
+
 const TARGET: &str = "dao_contract::propose::validate::state_transition()";
 
 #[derive(Debug, Clone, thiserror::Error)]
 pub enum Error {
+    #[error("Invalid input merkle root")]
+    InvalidInputMerkleRoot,
+
     #[error("Invalid DAO merkle root")]
     InvalidDaoMerkleRoot,
 
@@ -48,8 +53,11 @@ pub struct CallData {
 impl CallDataBase for CallData {
     fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>> {
         let mut zk_publics = Vec::new();
+        let mut total_funds_commit = pallas::Point::identity();
 
+        assert!(self.inputs.len() > 0, "inputs length cannot be zero");
         for input in &self.inputs {
+            total_funds_commit += input.value_commit;
             let value_coords = input.value_commit.to_affine().coordinates().unwrap();
             let value_commit_x = *value_coords.x();
             let value_commit_y = *value_coords.y();
@@ -68,7 +76,7 @@ impl CallDataBase for CallData {
             ]);
         }
 
-        let total_funds_coords = self.header.total_funds_commit.to_affine().coordinates().unwrap();
+        let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
         let total_funds_x = *total_funds_coords.x();
         let total_funds_y = *total_funds_coords.y();
         zk_publics.push(
@@ -104,8 +112,6 @@ pub struct Header {
     pub dao_merkle_root: MerkleNode,
     pub token_commit: pallas::Base,
     pub proposal_bulla: pallas::Base,
-    // TODO: compute from sum of input commits
-    pub total_funds_commit: pallas::Point,
 }
 
 #[derive(Clone, SerialEncodable, SerialDecodable)]
@@ -129,6 +135,14 @@ pub fn state_transition(
     // This will be inside wasm so unwrap is fine.
     let call_data = call_data.unwrap();
 
+    // Check the merkle roots for the input coins are valid
+    for input in &call_data.inputs {
+        let money_state = states.lookup::<MoneyState>(&"Money".to_string()).unwrap();
+        if !money_state.is_valid_merkle(&input.merkle_root) {
+            return Err(Error::InvalidInputMerkleRoot)
+        }
+    }
+
     let state = states.lookup::<State>(&"DAO".to_string()).unwrap();
 
     // Is the DAO bulla generated in the ZK proof valid

+ 14 - 20
bin/daod/src/dao_contract/propose/wallet.rs

@@ -70,15 +70,16 @@ impl Builder {
     pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall {
         let mut proofs = vec![];
 
-        let token_blind = pallas::Base::random(&mut OsRng);
+        let gov_token_blind = pallas::Base::random(&mut OsRng);
 
         let mut inputs = vec![];
         let mut total_funds = 0;
-        let mut input_funds_blinds = vec![];
+        let mut total_funds_blinds = pallas::Scalar::from(0);
         let mut signature_secrets = vec![];
         for input in self.inputs {
             let funds_blind = pallas::Scalar::random(&mut OsRng);
-            input_funds_blinds.push(funds_blind);
+            total_funds += input.note.value;
+            total_funds_blinds += funds_blind;
 
             let signature_secret = SecretKey::random(&mut OsRng);
             let signature_public = PublicKey::from_secret(signature_secret);
@@ -98,11 +99,13 @@ impl Builder {
             let prover_witnesses = vec![
                 Witness::Base(Value::known(input.secret.0)),
                 Witness::Base(Value::known(note.serial)),
+                Witness::Base(Value::known(pallas::Base::from(0))),
+                Witness::Base(Value::known(pallas::Base::from(0))),
                 Witness::Base(Value::known(pallas::Base::from(note.value))),
                 Witness::Base(Value::known(note.token_id)),
                 Witness::Base(Value::known(note.coin_blind)),
                 Witness::Scalar(Value::known(funds_blind)),
-                Witness::Base(Value::known(token_blind)),
+                Witness::Base(Value::known(gov_token_blind)),
                 Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
                 Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
                 Witness::Base(Value::known(signature_secret.0)),
@@ -136,7 +139,7 @@ impl Builder {
                 current
             };
 
-            let token_commit = poseidon_hash::<2>([note.token_id, token_blind]);
+            let token_commit = poseidon_hash::<2>([note.token_id, gov_token_blind]);
             assert_eq!(self.dao.gov_token_id, note.token_id);
 
             let value_commit = pedersen_commitment_u64(note.value, funds_blind);
@@ -159,8 +162,9 @@ impl Builder {
             let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
 
             let proving_key = &zk_info.proving_key;
-            let main_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
+            let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
                 .expect("DAO::propose() proving error!");
+            proofs.push(input_proof);
 
             // First we make the tx then sign after
             signature_secrets.push(signature_secret);
@@ -169,17 +173,12 @@ impl Builder {
             inputs.push(input);
         }
 
-        let mut total_funds_blind = pallas::Scalar::from(0);
-        for blind in &input_funds_blinds {
-            total_funds_blind += blind;
-        }
-        let total_funds_commit = pedersen_commitment_u64(total_funds, total_funds_blind);
+        let total_funds_commit = pedersen_commitment_u64(total_funds, total_funds_blinds);
         let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
         let total_funds_x = *total_funds_coords.x();
         let total_funds_y = *total_funds_coords.y();
         let total_funds = pallas::Base::from(total_funds);
 
-        let gov_token_blind = pallas::Base::random(&mut OsRng);
         let token_commit = poseidon_hash::<2>([self.dao.gov_token_id, gov_token_blind]);
 
         let proposal_dest_coords = self.proposal.dest.0.to_affine().coordinates().unwrap();
@@ -232,7 +231,7 @@ impl Builder {
         let prover_witnesses = vec![
             // Proposers total number of gov tokens
             Witness::Base(Value::known(total_funds)),
-            Witness::Scalar(Value::known(total_funds_blind)),
+            Witness::Scalar(Value::known(total_funds_blinds)),
             // Used for blinding exported gov token ID
             Witness::Base(Value::known(gov_token_blind)),
             // proposal params
@@ -267,12 +266,7 @@ impl Builder {
             .expect("DAO::propose() proving error!");
         proofs.push(main_proof);
 
-        let header = Header {
-            dao_merkle_root: self.dao_merkle_root,
-            proposal_bulla,
-            token_commit,
-            total_funds_commit,
-        };
+        let header = Header { dao_merkle_root: self.dao_merkle_root, proposal_bulla, token_commit };
 
         let mut unsigned_tx_data = vec![];
         header.encode(&mut unsigned_tx_data).expect("failed to encode data");
@@ -285,7 +279,7 @@ impl Builder {
             signatures.push(signature);
         }
 
-        let call_data = CallData { header, inputs: vec![], signatures: vec![] };
+        let call_data = CallData { header, inputs, signatures };
 
         FuncCall {
             contract_id: "DAO".to_string(),

+ 21 - 7
bin/daod/src/demo.rs

@@ -121,20 +121,34 @@ impl Transaction {
     fn zk_verify(&self, zk_bins: &ZkContractTable) {
         for func_call in &self.func_calls {
             let proofs_public_vals = &func_call.call_data.zk_public_values();
-            let proofs_keys = &func_call.call_data.zk_proof_addrs();
-            assert_eq!(proofs_public_vals.len(), proofs_keys.len());
-            assert_eq!(proofs_keys.len(), func_call.proofs.len());
-            for (key, (proof, public_vals)) in
-                zip!(proofs_keys, &func_call.proofs, proofs_public_vals)
+            let proofs_addrs = &func_call.call_data.zk_proof_addrs();
+            assert_eq!(
+                proofs_public_vals.len(),
+                proofs_addrs.len(),
+                "proof_public_vals.len()={} and proof_addrs.len()={} do not match",
+                proofs_public_vals.len(),
+                proofs_addrs.len(),
+            );
+            assert_eq!(
+                proofs_addrs.len(),
+                func_call.proofs.len(),
+                "proof_addrs.len()={} and func_call.proofs.len()={} do not match",
+                proofs_addrs.len(),
+                func_call.proofs.len()
+            );
+            for (i, (key, (proof, public_vals))) in
+                zip!(proofs_addrs, &func_call.proofs, proofs_public_vals).enumerate()
             {
                 match zk_bins.lookup(key).unwrap() {
                     ZkContractInfo::Binary(info) => {
                         let verifying_key = &info.verifying_key;
-                        proof.verify(&verifying_key, public_vals).expect("verify zk proof failed!");
+                        let verify_result = proof.verify(&verifying_key, public_vals);
+                        assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
                     }
                     ZkContractInfo::Native(info) => {
                         let verifying_key = &info.verifying_key;
-                        proof.verify(&verifying_key, public_vals).expect("verify zk proof failed!");
+                        let verify_result = proof.verify(&verifying_key, public_vals);
+                        assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
                     }
                 };
                 debug!("zk_verify({}) passed", key);