diff --git a/bin/daod/proof/dao-propose-main.zk b/bin/daod/proof/dao-propose-main.zk index 61c00d316..d28261667 100644 --- a/bin/daod/proof/dao-propose-main.zk +++ b/bin/daod/proof/dao-propose-main.zk @@ -1,20 +1,29 @@ constant "DaoProposeMain" { + EcFixedPointShort VALUE_COMMIT_VALUE, + EcFixedPoint VALUE_COMMIT_RANDOM, } contract "DaoProposeMain" { + # Proposers total number of gov tokens + Base total_funds, + Scalar total_funds_blind, + + # Check the inputs and this proof are for the same token + Base gov_token_blind, + # proposal params - #Base proposal_x, - #Base proposal_y, - #Base proposal_amount, - #Base proposal_serial, - #Base proposal_token_id, - #Base proposal_blind, + Base proposal_x, + Base proposal_y, + Base proposal_amount, + Base proposal_serial, + Base proposal_token_id, + Base proposal_blind, # DAO params Base dao_proposer_limit, Base dao_quorum, Base dao_approval_ratio, - Base gdrk_token_id, + Base gov_token_id, Base dao_public_x, Base dao_public_y, Base dao_bulla_blind, @@ -24,11 +33,14 @@ contract "DaoProposeMain" { } circuit "DaoProposeMain" { + token_commit = poseidon_hash(gov_token_id, gov_token_blind); + constrain_instance(token_commit); + dao_bulla = poseidon_hash( dao_proposer_limit, dao_quorum, dao_approval_ratio, - gdrk_token_id, + gov_token_id, dao_public_x, dao_public_y, dao_bulla_blind, @@ -38,5 +50,29 @@ circuit "DaoProposeMain" { dao_root = calculate_merkle_root(dao_leaf_pos, dao_path, dao_bulla); constrain_instance(dao_root); # Proves this DAO is valid + + # Rangeproof check for proposal amount + # TODO: waiting on this opcode in zkas + # + # greater_than_zero(amount) + # + # Use this temporary workaround. ec_mul_short() does an internal rangeproof + rangeproof = ec_mul_short(proposal_amount, VALUE_COMMIT_VALUE); + + # TODO: check total_funds >= proposer_limit + # + # greater_than_or_equal(total_funds, proposer_limit) + # + + # Pedersen commitment for coin's value + vcv = ec_mul_short(total_funds, VALUE_COMMIT_VALUE); + vcr = ec_mul(total_funds_blind, VALUE_COMMIT_RANDOM); + total_funds_commit = ec_add(vcv, vcr); + # Since total_funds_commit is a curve point, we fetch its coordinates + # and constrain them: + total_funds_commit_x = ec_get_x(total_funds_commit); + total_funds_commit_y = ec_get_y(total_funds_commit); + constrain_instance(total_funds_commit_x); + constrain_instance(total_funds_commit_y); } diff --git a/bin/daod/src/dao_contract/propose/validate.rs b/bin/daod/src/dao_contract/propose/validate.rs index 7d9b0d361..11e7ecc5c 100644 --- a/bin/daod/src/dao_contract/propose/validate.rs +++ b/bin/daod/src/dao_contract/propose/validate.rs @@ -22,11 +22,17 @@ type Result = std::result::Result; pub struct CallData { pub dao_merkle_root: MerkleNode, + pub token_commit: pallas::Base, + // TODO: compute from sum of input commits + pub total_funds_commit: pallas::Point, } impl CallDataBase for CallData { fn zk_public_values(&self) -> Vec> { - vec![vec![self.dao_merkle_root.0]] + let total_funds_coords = self.total_funds_commit.to_affine().coordinates().unwrap(); + let total_funds_x = *total_funds_coords.x(); + let total_funds_y = *total_funds_coords.y(); + vec![vec![self.token_commit, self.dao_merkle_root.0, total_funds_x, total_funds_y]] } fn zk_proof_addrs(&self) -> Vec { diff --git a/bin/daod/src/dao_contract/propose/wallet.rs b/bin/daod/src/dao_contract/propose/wallet.rs index 710d859f1..85c8d9169 100644 --- a/bin/daod/src/dao_contract/propose/wallet.rs +++ b/bin/daod/src/dao_contract/propose/wallet.rs @@ -18,6 +18,7 @@ use darkfi::{ DrkCircuitField, DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData, DrkUserDataBlind, DrkValueBlind, }, + util::{pedersen_commitment_base, pedersen_commitment_u64}, Proof, }, util::serial::{Encodable, SerialDecodable, SerialEncodable}, @@ -66,6 +67,17 @@ pub struct Builder { impl Builder { pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall { + let total_funds = 110; + let total_funds_blind = pallas::Scalar::random(&mut OsRng); + let total_funds_commit = pedersen_commitment_u64(total_funds, total_funds_blind); + 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(); let proposal_dest_x = *proposal_dest_coords.x(); let proposal_dest_y = *proposal_dest_coords.y(); @@ -102,14 +114,18 @@ impl Builder { }; let zk_bin = zk_info.bincode.clone(); let prover_witnesses = vec![ + // Proposers total number of gov tokens + Witness::Base(Value::known(total_funds)), + Witness::Scalar(Value::known(total_funds_blind)), + // Used for blinding exported gov token ID + Witness::Base(Value::known(gov_token_blind)), // proposal params - //Witness::Base(Value::known(proposal_dest_x)), - //Witness::Base(Value::known(proposal_dest_y)), - //Witness::Base(Value::known(proposal_amount)), - //Witness::Base(Value::known(self.proposal.serial)), - //Witness::Base(Value::known(self.proposal.token_id)), - //Witness::Base(Value::known(self.proposal.blind)), - + Witness::Base(Value::known(proposal_dest_x)), + Witness::Base(Value::known(proposal_dest_y)), + Witness::Base(Value::known(proposal_amount)), + Witness::Base(Value::known(self.proposal.serial)), + Witness::Base(Value::known(self.proposal.token_id)), + Witness::Base(Value::known(self.proposal.blind)), // DAO params Witness::Base(Value::known(dao_proposer_limit)), Witness::Base(Value::known(dao_quorum)), @@ -121,14 +137,16 @@ impl Builder { Witness::Uint32(Value::known(dao_leaf_position.try_into().unwrap())), Witness::MerklePath(Value::known(self.dao_merkle_path.try_into().unwrap())), ]; - let public_inputs = vec![self.dao_merkle_root.0]; + let public_inputs = + vec![token_commit, self.dao_merkle_root.0, total_funds_x, total_funds_y]; 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) .expect("DAO::propose() proving error!"); - let call_data = CallData { dao_merkle_root: self.dao_merkle_root }; + let call_data = + CallData { dao_merkle_root: self.dao_merkle_root, token_commit, total_funds_commit }; FuncCall { contract_id: "DAO".to_string(),