Răsfoiți Sursa

contract/money: moved the minted coin encrypted note from auth to actual token mint so its self contained plus some minor cleanup

skoupidi 2 luni în urmă
părinte
comite
610493b72c

+ 11 - 27
bin/drk/src/money.rs

@@ -39,8 +39,8 @@ use darkfi_money_contract::{
         MoneyNote, OwnCoin,
     },
     model::{
-        Coin, Input, MoneyAuthTokenFreezeParamsV1, MoneyAuthTokenMintParamsV1, MoneyBurnParamsV1,
-        MoneyFeeParamsV1, MoneyGenesisMintParamsV1, MoneyPoWRewardParamsV1, MoneyTokenMintParamsV1,
+        Coin, Input, MoneyAuthTokenFreezeParamsV1, MoneyBurnParamsV1, MoneyFeeParamsV1,
+        MoneyGenesisMintParamsV1, MoneyPoWRewardParamsV1, MoneyTokenMintParamsV1,
         MoneyTransferParamsV1, Nullifier, Output, TokenId, DARK_TOKEN_ID,
     },
     MoneyFunction, MONEY_CONTRACT_ZKAS_FEE_NS_V1,
@@ -735,9 +735,9 @@ impl Drk {
         scan_cache: &mut ScanCache,
         call_idx: &usize,
         calls: &[DarkLeaf<ContractCall>],
-    ) -> Result<(Vec<Nullifier>, Vec<(Coin, Option<AeadEncryptedNote>, bool)>, Vec<TokenId>)> {
+    ) -> Result<(Vec<Nullifier>, Vec<(Coin, AeadEncryptedNote, bool)>, Vec<TokenId>)> {
         let mut nullifiers: Vec<Nullifier> = vec![];
-        let mut coins: Vec<(Coin, Option<AeadEncryptedNote>, bool)> = vec![];
+        let mut coins: Vec<(Coin, AeadEncryptedNote, bool)> = vec![];
         let mut freezes: Vec<TokenId> = vec![];
 
         let call = &calls[*call_idx];
@@ -748,7 +748,7 @@ impl Drk {
                 let params: MoneyFeeParamsV1 = deserialize_async(&data[9..]).await?;
                 nullifiers.push(params.input.nullifier);
                 if !params.output.tx_local {
-                    coins.push((params.output.coin, Some(params.output.note), false));
+                    coins.push((params.output.coin, params.output.note, false));
                 }
             }
             MoneyFunction::GenesisMintV1 => {
@@ -756,7 +756,7 @@ impl Drk {
                 let params: MoneyGenesisMintParamsV1 = deserialize_async(&data[1..]).await?;
                 for output in params.outputs {
                     if !output.tx_local {
-                        coins.push((output.coin, Some(output.note), false));
+                        coins.push((output.coin, output.note, false));
                     }
                 }
             }
@@ -764,7 +764,7 @@ impl Drk {
                 scan_cache.log(String::from("[parse_money_call] Found Money::PoWRewardV1 call"));
                 let params: MoneyPoWRewardParamsV1 = deserialize_async(&data[1..]).await?;
                 if !params.output.tx_local {
-                    coins.push((params.output.coin, Some(params.output.note), true));
+                    coins.push((params.output.coin, params.output.note, true));
                 }
             }
             MoneyFunction::TransferV1 => {
@@ -777,7 +777,7 @@ impl Drk {
 
                 for output in params.outputs {
                     if !output.tx_local {
-                        coins.push((output.coin, Some(output.note), false));
+                        coins.push((output.coin, output.note, false));
                     }
                 }
             }
@@ -791,7 +791,7 @@ impl Drk {
 
                 for output in params.outputs {
                     if !output.tx_local {
-                        coins.push((output.coin, Some(output.note), false));
+                        coins.push((output.coin, output.note, false));
                     }
                 }
             }
@@ -809,22 +809,7 @@ impl Drk {
             MoneyFunction::TokenMintV1 => {
                 scan_cache.log(String::from("[parse_money_call] Found Money::TokenMintV1 call"));
                 let params: MoneyTokenMintParamsV1 = deserialize_async(&data[1..]).await?;
-                // Grab the note from the child auth call
-                let child_idx = call.children_indexes[0];
-                let child_call = &calls[child_idx];
-                // TODO: Grab the encrypted note from custom auth calls
-                let note = match deserialize_async::<MoneyAuthTokenMintParamsV1>(
-                    &child_call.data.data[1..],
-                )
-                .await
-                {
-                    Ok(child_params) => Some(child_params.enc_note),
-                    Err(_) => {
-                        scan_cache.log(String::from("[parse_money_call] Found non-native contract Token mint authority, skipping its note."));
-                        None
-                    }
-                };
-                coins.push((params.coin, note, false))
+                coins.push((params.coin, params.enc_note, false))
             }
             MoneyFunction::BurnV1 => {
                 scan_cache.log(String::from("[parse_money_call] Found Money::BurnV1 call"));
@@ -847,7 +832,7 @@ impl Drk {
         tree: &mut MerkleTree,
         secrets: &[SecretKey],
         messages_buffer: &mut Vec<String>,
-        coins: &[(Coin, Option<AeadEncryptedNote>, bool)],
+        coins: &[(Coin, AeadEncryptedNote, bool)],
     ) -> Result<(Vec<OwnCoin>, Option<SecretKey>)> {
         // Keep track of our own coins found in the vec
         let mut owncoins = vec![];
@@ -869,7 +854,6 @@ impl Drk {
 
             // Attempt to decrypt the note
             for secret in secrets {
-                let Some(note) = note else { continue };
                 let Ok(note) = note.decrypt::<MoneyNote>(secret) else { continue };
                 messages_buffer.push(String::from(
                     "[handle_money_call_coins] Successfully decrypted a Money Note",

+ 13 - 9
src/contract/money/proof/token_mint_v1.zk

@@ -9,6 +9,12 @@ constant "TokenMint_V1" {
 }
 
 witness "TokenMint_V1" {
+    # TokenAttributes {
+    Base token_auth_function,
+    Base token_user_data,
+    Base token_blind,
+    # }
+
     # CoinAttributes {
     Base coin_public_x,
     Base coin_public_y,
@@ -17,20 +23,16 @@ witness "TokenMint_V1" {
     Base coin_user_data,
     Base coin_blind,
     # }
-
-    # TokenAttributes {
-    Base token_auth_parent,
-    Base token_user_data,
-    Base token_blind,
-    # }
 }
 
 circuit "TokenMint_V1" {
+    # Constrain the token authority function
+    constrain_instance(token_auth_function);
+
     # Derive the token ID
-    token_id = poseidon_hash(token_auth_parent, token_user_data, token_blind);
-    constrain_instance(token_auth_parent);
+    token_id = poseidon_hash(token_auth_function, token_user_data, token_blind);
 
-    # Then show the coin contains the token ID
+    # Then constrain that the derived minted coin contains the token ID
     coin = poseidon_hash(
         coin_public_x,
         coin_public_y,
@@ -41,4 +43,6 @@ circuit "TokenMint_V1" {
         coin_blind,
     );
     constrain_instance(coin);
+
+    # At this point we've enforced all of our public inputs.
 }

+ 3 - 23
src/contract/money/src/client/auth_token_mint_v1.rs

@@ -21,17 +21,11 @@ use darkfi::{
     zkas::ZkBinary,
     Result,
 };
-use darkfi_sdk::{
-    crypto::{note::AeadEncryptedNote, Blind, Keypair},
-    pasta::pallas,
-};
+use darkfi_sdk::{crypto::Keypair, pasta::pallas};
 use rand::rngs::OsRng;
 use tracing::debug;
 
-use crate::{
-    client::MoneyNote,
-    model::{CoinAttributes, MoneyAuthTokenMintParamsV1, TokenAttributes},
-};
+use crate::model::{CoinAttributes, MoneyAuthTokenMintParamsV1, TokenAttributes};
 
 pub struct AuthTokenMintCallDebris {
     pub params: MoneyAuthTokenMintParamsV1,
@@ -89,21 +83,7 @@ impl AuthTokenMintCallBuilder {
         let circuit = ZkCircuit::new(prover_witnesses, &self.auth_mint_zkbin);
         let proof = Proof::create(&self.auth_mint_pk, &[circuit], &public_inputs, &mut OsRng)?;
 
-        // Create the note
-        let note = MoneyNote {
-            value: self.coin_attrs.value,
-            token_id: self.coin_attrs.token_id,
-            spend_hook: self.coin_attrs.spend_hook,
-            user_data: self.coin_attrs.user_data,
-            coin_blind: self.coin_attrs.blind,
-            value_blind: Blind::random(&mut OsRng),
-            token_blind: Blind::ZERO,
-            memo: vec![],
-        };
-
-        let enc_note = AeadEncryptedNote::encrypt(&note, &self.coin_attrs.public_key, &mut OsRng)?;
-
-        let params = MoneyAuthTokenMintParamsV1 { token_id, enc_note, mint_pubkey };
+        let params = MoneyAuthTokenMintParamsV1 { token_id, mint_pubkey };
         let debris = AuthTokenMintCallDebris { params, proofs: vec![proof] };
         Ok(debris)
     }

+ 27 - 7
src/contract/money/src/client/token_mint_v1.rs

@@ -21,11 +21,17 @@ use darkfi::{
     zkas::ZkBinary,
     Result,
 };
-use darkfi_sdk::pasta::pallas;
+use darkfi_sdk::{
+    crypto::{note::AeadEncryptedNote, Blind},
+    pasta::pallas,
+};
 use rand::rngs::OsRng;
 use tracing::debug;
 
-use crate::model::{CoinAttributes, MoneyTokenMintParamsV1, TokenAttributes};
+use crate::{
+    client::MoneyNote,
+    model::{CoinAttributes, MoneyTokenMintParamsV1, TokenAttributes},
+};
 
 pub struct TokenMintCallDebris {
     pub params: MoneyTokenMintParamsV1,
@@ -49,6 +55,10 @@ impl TokenMintCallBuilder {
         let (public_x, public_y) = self.coin_attrs.public_key.xy();
 
         let prover_witnesses = vec![
+            // Token attributes
+            Witness::Base(Value::known(self.token_attrs.auth_parent.inner())),
+            Witness::Base(Value::known(self.token_attrs.user_data)),
+            Witness::Base(Value::known(self.token_attrs.blind.inner())),
             // Coin attributes
             Witness::Base(Value::known(public_x)),
             Witness::Base(Value::known(public_y)),
@@ -56,10 +66,6 @@ impl TokenMintCallBuilder {
             Witness::Base(Value::known(self.coin_attrs.spend_hook.inner())),
             Witness::Base(Value::known(self.coin_attrs.user_data)),
             Witness::Base(Value::known(self.coin_attrs.blind.inner())),
-            // Token attributes
-            Witness::Base(Value::known(self.token_attrs.auth_parent.inner())),
-            Witness::Base(Value::known(self.token_attrs.user_data)),
-            Witness::Base(Value::known(self.token_attrs.blind.inner())),
         ];
 
         let coin = self.coin_attrs.to_coin();
@@ -70,7 +76,21 @@ impl TokenMintCallBuilder {
         let circuit = ZkCircuit::new(prover_witnesses, &self.mint_zkbin);
         let proof = Proof::create(&self.mint_pk, &[circuit], &public_inputs, &mut OsRng)?;
 
-        let params = MoneyTokenMintParamsV1 { coin };
+        // Create the note
+        let note = MoneyNote {
+            value: self.coin_attrs.value,
+            token_id: self.coin_attrs.token_id,
+            spend_hook: self.coin_attrs.spend_hook,
+            user_data: self.coin_attrs.user_data,
+            coin_blind: self.coin_attrs.blind,
+            value_blind: Blind::random(&mut OsRng),
+            token_blind: Blind::ZERO,
+            memo: vec![],
+        };
+
+        let enc_note = AeadEncryptedNote::encrypt(&note, &self.coin_attrs.public_key, &mut OsRng)?;
+
+        let params = MoneyTokenMintParamsV1 { coin, enc_note };
         let debris = TokenMintCallDebris { params, proofs: vec![proof] };
         Ok(debris)
     }

+ 10 - 7
src/contract/money/src/entrypoint/token_mint_v1.rs

@@ -51,10 +51,10 @@ pub(crate) fn money_token_mint_get_metadata_v1(
         );
         return Err(MoneyError::ChildrenIndexesLengthMismatch.into())
     }
-    let child_idx = self_.children_indexes[0];
-    let child_call = &calls[child_idx].data;
-    let child_contract_id = child_call.contract_id;
-    let child_func_code = child_call.data[0];
+    let auth_idx = self_.children_indexes[0];
+    let auth_call = &calls[auth_idx].data;
+    let auth_contract_id = auth_call.contract_id;
+    let auth_func_code = auth_call.data[0];
 
     let params: MoneyTokenMintParamsV1 = deserialize(&self_.data.data[1..])?;
 
@@ -63,12 +63,15 @@ pub(crate) fn money_token_mint_get_metadata_v1(
     // Public keys for the transaction signatures we have to verify.
     let signature_pubkeys: Vec<PublicKey> = vec![];
 
-    let child_func_id =
-        FuncRef { contract_id: child_contract_id, func_code: child_func_code }.to_func_id();
+    // Derive the mint authority function ID
+    let auth_func_id =
+        FuncRef { contract_id: auth_contract_id, func_code: auth_func_code }.to_func_id();
 
+    // In ZK we verify that the minted coin is properly derived from
+    // using the authority token ID.
     zk_public_inputs.push((
         MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1.to_string(),
-        vec![child_func_id.inner(), params.coin.inner()],
+        vec![auth_func_id.inner(), params.coin.inner()],
     ));
 
     // Serialize everything gathered and return it

+ 1 - 1
src/contract/money/src/model/mod.rs

@@ -241,6 +241,7 @@ pub struct MoneyGenesisMintUpdateV1 {
 pub struct MoneyTokenMintParamsV1 {
     /// The newly minted coin
     pub coin: Coin,
+    pub enc_note: AeadEncryptedNote,
 }
 
 /// State update for `Money::TokenMint`
@@ -254,7 +255,6 @@ pub struct MoneyTokenMintUpdateV1 {
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 pub struct MoneyAuthTokenMintParamsV1 {
     pub token_id: TokenId,
-    pub enc_note: AeadEncryptedNote,
     pub mint_pubkey: PublicKey,
 }
 

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

@@ -176,7 +176,7 @@ impl TestHarness {
         holder: &Holder,
         tx: Transaction,
         mint_params: &MoneyTokenMintParamsV1,
-        auth_params: &MoneyAuthTokenMintParamsV1,
+        _auth_params: &MoneyAuthTokenMintParamsV1,
         fee_params: &Option<MoneyFeeParamsV1>,
         block_height: u32,
         append: bool,
@@ -192,7 +192,7 @@ impl TestHarness {
 
             // Process the minted coin output
             wallet.money_merkle_tree.append(MerkleNode::from(mint_params.coin.inner()));
-            if let Ok(note) = auth_params.enc_note.decrypt::<MoneyNote>(&wallet.keypair.secret) {
+            if let Ok(note) = mint_params.enc_note.decrypt::<MoneyNote>(&wallet.keypair.secret) {
                 let owncoin = OwnCoin {
                     coin: mint_params.coin,
                     note: note.clone(),

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

@@ -49,8 +49,8 @@ use tracing::debug;
 
 /// Update these if any circuits are changed.
 /// Delete the existing cachefiles, and enable debug logging, you will see the new hashes.
-const PKS_HASH: &str = "f0788d23abe5afe9778f3856c6a816619e8943028c149213d4ebcb502678b87e";
-const VKS_HASH: &str = "106e8ac76f003740d5e16ef1fcf74dee068cdc238a6bb7a0a7832ef3bf863911";
+const PKS_HASH: &str = "1dd7149b2ebdaffa4843fa22aafc8af141a6f829f5acab542e1c588171ad1a08";
+const VKS_HASH: &str = "3b3cc2e7346225de1b331d7893f1baee8f3887af7c9b0b0f62bc2ad4dab0e46d";
 
 /// Build a `PathBuf` to a cachefile
 fn cache_path(typ: &str) -> Result<PathBuf> {

+ 0 - 3
src/sdk/python/src/contract/money/auth_token_mint_v1.rs

@@ -32,7 +32,6 @@ impl FunctionParams for money_model::MoneyAuthTokenMintParamsV1 {
     fn to_pydict(&self, py: Python) -> PyResult<Py<PyDict>> {
         let dict = PyDict::new(py);
         dict.set_item("token_id", self.token_id.to_string())?;
-        dict.set_item("enc_note", self.enc_note.to_pydict(py)?)?;
         dict.set_item("mint_pubkey", self.mint_pubkey.to_string())?;
         Ok(dict.unbind())
     }
@@ -41,8 +40,6 @@ impl FunctionParams for money_model::MoneyAuthTokenMintParamsV1 {
         let prefix = format!("{}├─ ", "   ".repeat(depth));
         writeln!(out, "{prefix}token_id: {}", self.token_id).unwrap();
         writeln!(out, "{prefix}mint_pubkey: {}", self.mint_pubkey).unwrap();
-        writeln!(out, "{prefix}enc_note:").unwrap();
-        self.enc_note.fmt_pretty(out, depth + 2)?;
         Ok(())
     }
 }

+ 3 - 0
src/sdk/python/src/contract/money/token_mint_v1.rs

@@ -32,12 +32,15 @@ impl FunctionParams for money_model::MoneyTokenMintParamsV1 {
     fn to_pydict(&self, py: Python) -> PyResult<Py<PyDict>> {
         let dict = PyDict::new(py);
         dict.set_item("coin", self.coin.to_string())?;
+        dict.set_item("enc_note", self.enc_note.to_pydict(py)?)?;
         Ok(dict.unbind())
     }
 
     fn fmt_pretty(&self, out: &mut String, depth: usize) -> PyResult<()> {
         let prefix = format!("{}├─ ", "   ".repeat(depth));
         writeln!(out, "{prefix}coin: {}", self.coin).unwrap();
+        writeln!(out, "{prefix}enc_note:").unwrap();
+        self.enc_note.fmt_pretty(out, depth + 2)?;
         Ok(())
     }
 }