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

Derive TokenID with a derivation prefix.

parazyd 3 лет назад
Родитель
Сommit
1a540c67e0

+ 1 - 6
bin/drk/src/wallet_money.rs

@@ -521,19 +521,14 @@ impl Drk {
             if call.contract_id == cid && call.data[0] == MoneyFunction::TokenMintV1 as u8 {
                 eprintln!("Found Money::MintV1 in call {}", i);
                 let params: MoneyTokenMintParamsV1 = deserialize(&call.data[1..])?;
-
                 outputs.push(params.output);
-
                 continue
             }
 
             if call.contract_id == cid && call.data[0] == MoneyFunction::TokenFreezeV1 as u8 {
                 eprintln!("Found Money::FreezeV1 in call {}", i);
                 let params: MoneyTokenFreezeParamsV1 = deserialize(&call.data[1..])?;
-
-                let (mint_x, mint_y) = params.signature_public.xy();
-                let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
-
+                let token_id = TokenId::derive_public(params.signature_public);
                 freezes.push(token_id);
             }
         }

+ 6 - 4
src/contract/money/proof/token_freeze_v1.zk

@@ -8,15 +8,17 @@ witness "TokenFreeze_V1" {
 }
 
 circuit "TokenFreeze_V1" {
+	# TokenID derivation path (See darkfi_sdk::crypto::ContractId)
+	derivation_path = witness_base(69);
+
 	# Derive public key for the mint authority
 	mint_public = ec_mul_base(mint_authority, NULLIFIER_K);
 	mint_x = ec_get_x(mint_public);
 	mint_y = ec_get_y(mint_public);
-	# I don't think we need to enforce these two as public inputs
-	#constrain_instance(mint_x);
-	#constrain_instance(mint_y);
+	constrain_instance(mint_x);
+	constrain_instance(mint_y);
 
 	# Derive the token ID
-	token_id = poseidon_hash(mint_x, mint_y);
+	token_id = poseidon_hash(derivation_path, mint_x, mint_y);
 	constrain_instance(token_id);
 }

+ 6 - 4
src/contract/money/proof/token_mint_v1.zk

@@ -31,16 +31,18 @@ witness "TokenMint_V1" {
 circuit "TokenMint_V1" {
 	# TODO: verify if supply must be > 0 and add corresponding opcode
 
+	# TokenID derivation path (See darkfi_sdk::crypto::TokenId)
+	derivation_path = witness_base(69);
+
 	# Derive public key for the mint authority
 	mint_public = ec_mul_base(mint_authority, NULLIFIER_K);
 	mint_x = ec_get_x(mint_public);
 	mint_y = ec_get_y(mint_public);
-	# I don't think we need to have these two as public inputs
-	#constrain_instance(mint_x);
-	#constrain_instance(mint_y);
+	constrain_instance(mint_x);
+	constrain_instance(mint_y);
 
 	# Derive the token ID
-	token_id = poseidon_hash(mint_x, mint_y);
+	token_id = poseidon_hash(derivation_path, mint_x, mint_y);
 	constrain_instance(token_id);
 
 	# Poseidon hash of the minted coin

+ 6 - 5
src/contract/money/src/client/token_freeze_v1.rs

@@ -22,7 +22,7 @@ use darkfi::{
     Result,
 };
 use darkfi_sdk::{
-    crypto::{poseidon_hash, Keypair, TokenId},
+    crypto::{Keypair, PublicKey, TokenId},
     pasta::pallas,
 };
 use log::{debug, info};
@@ -36,12 +36,14 @@ pub struct TokenFreezeCallDebris {
 }
 
 pub struct TokenFreezeRevealed {
+    pub signature_public: PublicKey,
     pub token_id: TokenId,
 }
 
 impl TokenFreezeRevealed {
     pub fn to_vec(&self) -> Vec<pallas::Base> {
-        vec![self.token_id.inner()]
+        let (sig_x, sig_y) = self.signature_public.xy();
+        vec![sig_x, sig_y, self.token_id.inner()]
     }
 }
 
@@ -79,10 +81,9 @@ pub(crate) fn create_token_freeze_proof(
     pk: &ProvingKey,
     mint_authority: &Keypair,
 ) -> Result<(Proof, TokenFreezeRevealed)> {
-    let (mint_x, mint_y) = mint_authority.public.xy();
-    let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
+    let token_id = TokenId::derive(mint_authority.secret);
 
-    let public_inputs = TokenFreezeRevealed { token_id };
+    let public_inputs = TokenFreezeRevealed { signature_public: mint_authority.public, token_id };
 
     let prover_witnesses = vec![Witness::Base(Value::known(mint_authority.secret.inner()))];
 

+ 13 - 5
src/contract/money/src/client/token_mint_v1.rs

@@ -45,6 +45,7 @@ pub struct TokenMintCallDebris {
 }
 
 pub struct TokenMintRevealed {
+    pub signature_public: PublicKey,
     pub token_id: TokenId,
     pub coin: Coin,
     pub value_commit: pallas::Point,
@@ -53,12 +54,15 @@ pub struct TokenMintRevealed {
 
 impl TokenMintRevealed {
     pub fn to_vec(&self) -> Vec<pallas::Base> {
+        let (sig_x, sig_y) = self.signature_public.xy();
         let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
         let tokcom_coords = self.token_commit.to_affine().coordinates().unwrap();
 
         // NOTE: It's important to keep these in the same order
         // as the `constrain_instance` calls in the zkas code.
         vec![
+            sig_x,
+            sig_y,
             self.token_id.inner(),
             self.coin.inner(),
             *valcom_coords.x(),
@@ -94,8 +98,7 @@ impl TokenMintCallBuilder {
 
         // In this call, we will build one clear input and one anonymous output.
         // The mint authority pubkey is used to derive the token ID.
-        let (mint_x, mint_y) = self.mint_authority.public.xy();
-        let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
+        let token_id = TokenId::derive(self.mint_authority.secret);
 
         let input = TransactionBuilderClearInputInfo {
             value: self.amount,
@@ -181,8 +184,7 @@ pub fn create_token_mint_proof(
     user_data: pallas::Base,
     coin_blind: pallas::Base,
 ) -> Result<(Proof, TokenMintRevealed)> {
-    let (mint_x, mint_y) = mint_authority.public.xy();
-    let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
+    let token_id = TokenId::derive(mint_authority.secret);
 
     let value_commit = pedersen_commitment_u64(output.value, value_blind);
     let token_commit = pedersen_commitment_base(token_id.inner(), token_blind);
@@ -200,7 +202,13 @@ pub fn create_token_mint_proof(
         coin_blind,
     ]));
 
-    let public_inputs = TokenMintRevealed { token_id, coin, value_commit, token_commit };
+    let public_inputs = TokenMintRevealed {
+        signature_public: mint_authority.public,
+        token_id,
+        coin,
+        value_commit,
+        token_commit,
+    };
 
     let prover_witnesses = vec![
         Witness::Base(Value::known(mint_authority.secret.inner())),

+ 10 - 10
src/contract/money/src/entrypoint/token_freeze_v1.rs

@@ -17,7 +17,7 @@
  */
 
 use darkfi_sdk::{
-    crypto::{poseidon_hash, ContractId, PublicKey, TokenId},
+    crypto::{ContractId, PublicKey, TokenId},
     db::{db_contains_key, db_lookup, db_set},
     error::{ContractError, ContractResult},
     msg,
@@ -46,11 +46,15 @@ pub(crate) fn money_token_freeze_get_metadata_v1(
     // Public keys for the transaction signatures we have to verify
     let signature_pubkeys: Vec<PublicKey> = vec![params.signature_public];
 
-    let (mint_x, mint_y) = params.signature_public.xy();
-    let token_id = poseidon_hash([mint_x, mint_y]);
+    // Derive the TokenId from the public key
+    let (sig_x, sig_y) = params.signature_public.xy();
+    let token_id = TokenId::derive_public(params.signature_public);
 
     // In ZK we just verify that the token ID is properly derived from the authority.
-    zk_public_inputs.push((MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1.to_string(), vec![token_id]));
+    zk_public_inputs.push((
+        MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1.to_string(),
+        vec![sig_x, sig_y, token_id.inner()],
+    ));
 
     // Serialize everything gathered and return it
     let mut metadata = vec![];
@@ -72,8 +76,7 @@ pub(crate) fn money_token_freeze_process_instruction_v1(
     // We just check if the mint was already frozen beforehand
     let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
 
-    let (mint_x, mint_y) = params.signature_public.xy();
-    let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
+    let token_id = TokenId::derive_public(params.signature_public);
 
     // Check that the mint is not frozen
     if db_contains_key(token_freeze_db, &serialize(&token_id))? {
@@ -96,10 +99,7 @@ pub(crate) fn money_token_freeze_process_update_v1(
     update: MoneyTokenFreezeUpdateV1,
 ) -> ContractResult {
     let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
-
-    let (mint_x, mint_y) = update.signature_public.xy();
-    let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
-
+    let token_id = TokenId::derive_public(update.signature_public);
     msg!("[MintV1] Freezing mint for token {}", token_id);
     db_set(token_freeze_db, &serialize(&token_id), &[])?;
 

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

@@ -18,8 +18,8 @@
 
 use darkfi_sdk::{
     crypto::{
-        pasta_prelude::*, pedersen_commitment_base, pedersen_commitment_u64, poseidon_hash,
-        ContractId, MerkleNode, TokenId,
+        pasta_prelude::*, pedersen_commitment_base, pedersen_commitment_u64, ContractId,
+        MerkleNode, TokenId,
     },
     db::{db_contains_key, db_lookup, db_set},
     error::{ContractError, ContractResult},
@@ -54,18 +54,19 @@ pub(crate) fn money_token_mint_get_metadata_v1(
     // signed by the mint authority.
     let signature_pubkeys = vec![params.input.signature_public];
 
+    // Derive the TokenId from the public key
+    let (sig_x, sig_y) = params.input.signature_public.xy();
+    let token_id = TokenId::derive_public(params.input.signature_public);
+
     let value_coords = params.output.value_commit.to_affine().coordinates().unwrap();
     let token_coords = params.output.token_commit.to_affine().coordinates().unwrap();
 
-    // Since we expect a signature from the mint authority, we use those coordinates
-    // as public inputs for the ZK proof:
-    let (sig_x, sig_y) = params.input.signature_public.xy();
-    let token_id = poseidon_hash([sig_x, sig_y]);
-
     zk_public_inputs.push((
         MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1.to_string(),
         vec![
-            token_id,
+            sig_x,
+            sig_y,
+            token_id.inner(),
             params.output.coin.inner(),
             *value_coords.x(),
             *value_coords.y(),
@@ -97,8 +98,7 @@ pub(crate) fn money_token_mint_process_instruction_v1(
     let token_freeze_db = db_lookup(cid, MONEY_CONTRACT_TOKEN_FREEZE_TREE)?;
 
     // Check that the signature public key is actually the token ID
-    let (mint_x, mint_y) = params.input.signature_public.xy();
-    let token_id = TokenId::from(poseidon_hash([mint_x, mint_y]));
+    let token_id = TokenId::derive_public(params.input.signature_public);
     if token_id != params.input.token_id {
         msg!("[MintV1] Error: Token ID does not derive from mint authority");
         return Err(MoneyError::TokenIdDoesNotDeriveFromMint.into())

+ 13 - 3
src/sdk/src/crypto/token_id.rs

@@ -29,9 +29,12 @@ lazy_static! {
     // avoid hardcoding contract IDs for arbitrary contract deployments, because
     // the contracts with 0 as their x coordinate can never have a valid signature.
 
+    /// Derivation prefix for `TokenId`
+    pub static ref TOKEN_ID_PREFIX: pallas::Base = pallas::Base::from(69);
+
     /// Native DARK token ID
     pub static ref DARK_TOKEN_ID: TokenId =
-        TokenId::from(poseidon_hash([pallas::Base::zero(), pallas::Base::from(42)]));
+        TokenId::from(poseidon_hash([*TOKEN_ID_PREFIX, pallas::Base::zero(), pallas::Base::from(42)]));
 }
 
 /// TokenId represents an on-chain identifier for a certain token.
@@ -39,11 +42,18 @@ lazy_static! {
 pub struct TokenId(pallas::Base);
 
 impl TokenId {
-    /// Derives a `TokenId` given a `SecretKey` (mint authority)
+    /// Derives a `TokenId` from a `SecretKey` (mint authority)
     pub fn derive(mint_authority: SecretKey) -> Self {
         let public_key = PublicKey::from_secret(mint_authority);
         let (x, y) = public_key.xy();
-        let hash = poseidon_hash::<2>([x, y]);
+        let hash = poseidon_hash([*TOKEN_ID_PREFIX, x, y]);
+        Self(hash)
+    }
+
+    /// Derives a `TokenId` from a `PublicKey`
+    pub fn derive_public(public_key: PublicKey) -> Self {
+        let (x, y) = public_key.xy();
+        let hash = poseidon_hash([*TOKEN_ID_PREFIX, x, y]);
         Self(hash)
     }