Просмотр исходного кода

dao: apply same verifiable encryption for other outputs, to the DAO change output as well.

zero 2 лет назад
Родитель
Сommit
b1da730489

+ 1 - 2
src/contract/dao/proof/dao-auth-money-transfer-enc-coin.zk

@@ -21,11 +21,10 @@ witness "DaoAuthMoneyTransferEncCoin" {
 }
 
 circuit "DaoAuthMoneyTransferEncCoin" {
-    # UGLY HACK -----------------
+    # cast to EcPoint
     # (otherwise zkas refuses to compile)
     ONE = witness_base(1);
     pubkey = ec_mul_var_base(ONE, public_key);
-    # ---------------------------
 
     coin = poseidon_hash(
         ec_get_x(pubkey),

+ 45 - 4
src/contract/dao/proof/dao-auth-money-transfer.zk

@@ -4,6 +4,7 @@ field = "pallas";
 constant "DaoAuthMoneyTransfer" {
     EcFixedPointShort VALUE_COMMIT_VALUE,
     EcFixedPoint VALUE_COMMIT_RANDOM,
+    EcFixedPointBase NULLIFIER_K,
 }
 
 witness "DaoAuthMoneyTransfer" {
@@ -20,8 +21,7 @@ witness "DaoAuthMoneyTransfer" {
     Base dao_approval_ratio_quot,
     Base dao_approval_ratio_base,
     Base gov_token_id,
-    Base dao_public_x,
-    Base dao_public_y,
+    EcNiPoint dao_public_key,
     Base dao_bulla_blind,
 
     # Dao input(s) user data blind
@@ -29,14 +29,24 @@ witness "DaoAuthMoneyTransfer" {
 
     # Dao output coin attrs
     Base dao_value,
-    Base dao_token,
+    Base dao_token_id,
     Base dao_serial,
 
     # Should be set to DAO_CONTRACT_ID
     Base dao_contract_id,
+
+    # Epehemeral secret used for diffie-hellman shared secret derivation
+    Base ephem_secret,
 }
 
 circuit "DaoAuthMoneyTransfer" {
+    # cast to EcPoint
+    # (otherwise zkas refuses to compile)
+    ONE = witness_base(1);
+    dao_pubkey = ec_mul_var_base(ONE, dao_public_key);
+    dao_public_x = ec_get_x(dao_pubkey);
+    dao_public_y = ec_get_y(dao_pubkey);
+
     dao_bulla = poseidon_hash(
         dao_proposer_limit,
         dao_quorum,
@@ -74,7 +84,7 @@ circuit "DaoAuthMoneyTransfer" {
         # which ensures it will be correct.
         dao_value,
         # Likewise the token_id must match the other output coins.
-        dao_token,
+        dao_token_id,
         dao_serial,
         dao_contract_id,
         dao_bulla,
@@ -85,5 +95,36 @@ circuit "DaoAuthMoneyTransfer" {
     # Reveal content commit. This should contain the set of coins.
     # We check these are set in the runtime.
     constrain_instance(proposal_auth_calls_commit);
+
+    # Now do verifiable encryption for DAO change output
+
+    # Ephemeral public key
+    ephem_public = ec_mul_base(ephem_secret, NULLIFIER_K);
+    constrain_instance(ec_get_x(ephem_public));
+    constrain_instance(ec_get_y(ephem_public));
+
+    # The shared_point C = eP = dE
+    shared_point = ec_mul_var_base(ephem_secret, dao_public_key);
+    shared_secret = poseidon_hash(
+        ec_get_x(shared_point),
+        ec_get_y(shared_point),
+    );
+
+    const_1 = witness_base(1);
+    const_2 = witness_base(2);
+
+    # Value
+    enc_value = base_add(dao_value, shared_secret);
+    constrain_instance(enc_value);
+
+    # Token ID
+    shared_secret_1 = poseidon_hash(shared_secret, const_1);
+    enc_token_id = base_add(dao_token_id, shared_secret_1);
+    constrain_instance(enc_token_id);
+
+    # Serial
+    shared_secret_2 = poseidon_hash(shared_secret, const_2);
+    enc_serial = base_add(dao_serial, shared_secret_2);
+    constrain_instance(enc_serial);
 }
 

+ 34 - 6
src/contract/dao/src/client/auth_xfer.rs

@@ -122,15 +122,37 @@ impl DaoAuthMoneyTransferCall {
 
         // Build the main proof
 
-        let params = DaoAuthMoneyTransferParams { enc_attrs };
+        let ephem_secret = pallas::Base::random(&mut OsRng);
+        let change_ephem_pubkey = PublicKey::from_secret(ephem_secret.into());
+        let (ephem_x, ephem_y) = change_ephem_pubkey.xy();
+
+        let dao_public_key = self.dao.public_key.inner();
+        let dao_change_value = pallas::Base::from(self.dao_coin_attrs.value);
+
+        let shared_point = dao_public_key * mod_r_p(ephem_secret);
+        let shared_point_coords = shared_point.to_affine().coordinates().unwrap();
+        let (shared_point_x, shared_point_y) = (*shared_point_coords.x(), *shared_point_coords.y());
+        let shared_secret = poseidon_hash([shared_point_x, shared_point_y]);
+        let change_enc_value = dao_change_value + shared_secret;
+
+        let change_enc_token_id = self.dao_coin_attrs.token_id.inner() +
+            poseidon_hash([shared_secret, pallas::Base::from(1)]);
+        let change_enc_serial =
+            self.dao_coin_attrs.serial + poseidon_hash([shared_secret, pallas::Base::from(2)]);
+
+        let params = DaoAuthMoneyTransferParams {
+            enc_attrs,
+            change_enc_value,
+            change_enc_token_id,
+            change_enc_serial,
+            change_ephem_pubkey,
+        };
 
         let dao_proposer_limit = pallas::Base::from(self.dao.proposer_limit);
         let dao_quorum = pallas::Base::from(self.dao.quorum);
         let dao_approval_ratio_quot = pallas::Base::from(self.dao.approval_ratio_quot);
         let dao_approval_ratio_base = pallas::Base::from(self.dao.approval_ratio_base);
 
-        let (dao_pub_x, dao_pub_y) = self.dao.public_key.xy();
-
         let input_user_data_enc =
             poseidon_hash([self.dao.to_bulla().inner(), self.input_user_data_blind]);
 
@@ -147,17 +169,18 @@ impl DaoAuthMoneyTransferCall {
             Witness::Base(Value::known(dao_approval_ratio_quot)),
             Witness::Base(Value::known(dao_approval_ratio_base)),
             Witness::Base(Value::known(self.dao.gov_token_id.inner())),
-            Witness::Base(Value::known(dao_pub_x)),
-            Witness::Base(Value::known(dao_pub_y)),
+            Witness::EcNiPoint(Value::known(dao_public_key)),
             Witness::Base(Value::known(self.dao.bulla_blind)),
             // Dao input user data blind
             Witness::Base(Value::known(self.input_user_data_blind)),
             // Dao output coin attrs
-            Witness::Base(Value::known(pallas::Base::from(self.dao_coin_attrs.value))),
+            Witness::Base(Value::known(dao_change_value)),
             Witness::Base(Value::known(self.dao_coin_attrs.token_id.inner())),
             Witness::Base(Value::known(self.dao_coin_attrs.serial)),
             // DAO_CONTRACT_ID
             Witness::Base(Value::known(DAO_CONTRACT_ID.inner())),
+            // Encrypted change DAO output
+            Witness::Base(Value::known(ephem_secret)),
         ];
 
         let public_inputs = vec![
@@ -166,6 +189,11 @@ impl DaoAuthMoneyTransferCall {
             self.dao_coin_attrs.to_coin().inner(),
             DAO_CONTRACT_ID.inner(),
             self.proposal.auth_calls.commit(),
+            ephem_x,
+            ephem_y,
+            change_enc_value,
+            change_enc_token_id,
+            change_enc_serial,
         ];
 
         let circuit = ZkCircuit::new(prover_witnesses, auth_xfer_zkbin);

+ 6 - 0
src/contract/dao/src/entrypoint/auth_xfer.rs

@@ -84,6 +84,7 @@ pub(crate) fn dao_authxfer_get_metadata(
     // Also check the coin in the change output
     let last_coin = xfer_params.outputs.last().unwrap().coin;
 
+    let (ephem_x, ephem_y) = self_params.change_ephem_pubkey.xy();
     zk_public_inputs.push((
         DAO_CONTRACT_ZKAS_DAO_AUTH_MONEY_TRANSFER_NS.to_string(),
         vec![
@@ -92,6 +93,11 @@ pub(crate) fn dao_authxfer_get_metadata(
             last_coin.inner(),
             DAO_CONTRACT_ID.inner(),
             exec_params.proposal_auth_calls.commit(),
+            ephem_x,
+            ephem_y,
+            self_params.change_enc_value,
+            self_params.change_enc_token_id,
+            self_params.change_enc_serial,
         ],
     ));
 

+ 7 - 2
src/contract/dao/src/model.rs

@@ -365,18 +365,23 @@ pub struct DaoExecUpdate {
 /// Parameters for `Dao::AuthMoneyTransfer`
 pub struct DaoAuthMoneyTransferParams {
     pub enc_attrs: Vec<DaoAuthCoinAttrs>,
+
+    pub change_ephem_pubkey: PublicKey,
+    pub change_enc_value: pallas::Base,
+    pub change_enc_token_id: pallas::Base,
+    pub change_enc_serial: pallas::Base,
 }
 // ANCHOR_END: dao-auth_xfer-params
 
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
 // ANCHOR: dao-auth_coinattrs-params
 pub struct DaoAuthCoinAttrs {
+    pub ephem_pubkey: PublicKey,
+
     pub value: pallas::Base,
     pub token_id: pallas::Base,
     pub serial: pallas::Base,
     pub spend_hook: pallas::Base,
     pub user_data: pallas::Base,
-
-    pub ephem_pubkey: PublicKey,
 }
 // ANCHOR_END: dao-auth_coinattrs-params

+ 2 - 2
src/contract/test-harness/src/vks.rs

@@ -50,8 +50,8 @@ use darkfi_serial::{deserialize, serialize};
 use log::debug;
 
 /// Update this if any circuits are changed
-const VKS_HASH: &str = "9d99da4cc2fa2882e5529bb6b24a965a815a2a22dc699d5e58ad17182e9f92a7";
-const PKS_HASH: &str = "83f2577d4036bd92c2502d11b7af5c37bbe350bc17f2a2cd96bd4b7e16e4cebf";
+const VKS_HASH: &str = "81036e85adea1b407698b0a3f58020f69ed6ac6c7843243b8b7b026d165f237f";
+const PKS_HASH: &str = "40c0c448274dfe66ec4249a38e69b1c2f7fd971cc3d35fbb2129f4ee8ee8aea5";
 
 fn pks_path(typ: &str) -> Result<PathBuf> {
     let output = Command::new("git").arg("rev-parse").arg("--show-toplevel").output()?.stdout;