ソースを参照

contract/money: Rename zkas proofs and add token_id verification.

parazyd 3 年 前
コミット
0a961cc822

+ 0 - 78
src/contract/money/proof/lead_burn.zk

@@ -1,78 +0,0 @@
-constant "LeadBurn" {
-         EcFixedPointShort VALUE_COMMIT_VALUE,
-         EcFixedPoint VALUE_COMMIT_RANDOM,
-         EcFixedPointBase NULLIFIER_K,
-}
-
-contract "LeadBurn" {
-         MerklePath c1_cm_path,
-         Uint32 c1_cm_pos,
-         Uint32 c1_sk_pos,
-         Base c1_sk,
-         Base c1_sk_root,
-         MerklePath c1_sk_path,
-         Base c1_tau,
-         Base c1_rho,
-         Scalar c1_opening,
-         Base value,
-         Scalar value_blind,
-}
-
-circuit "LeadBurn" {
-        ZERO = witness_base(0);
-        PREFIX_CM = witness_base(4);
-        PREFIX_PK = witness_base(5);
-        PREFIX_SN = witness_base(6);
-
-        # value commitment
-        # necessary anonymously validading value state transition
-	vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
-	vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
-	value_commit = ec_add(vcv, vcr);
-	constrain_instance(ec_get_x(value_commit));
-	constrain_instance(ec_get_y(value_commit));
-        
-        # coin (1) pk
-        pk = poseidon_hash(
-           PREFIX_PK,
-           c1_sk_root,
-           c1_tau,
-           ZERO
-        );
-        constrain_instance(pk);
-        
-        # coin (1) cm/commitment
-        c1_cm_msg = poseidon_hash(
-                  PREFIX_CM,
-                  pk,
-                  value,
-                  c1_rho
-        );
-        c1_cm_v = ec_mul_base(c1_cm_msg, NULLIFIER_K);
-        c1_cm_r = ec_mul(c1_opening, VALUE_COMMIT_RANDOM);
-        c1_cm = ec_add(c1_cm_v, c1_cm_r);
-        c1_cm_x = ec_get_x(c1_cm);
-        c1_cm_y = ec_get_y(c1_cm);
-        c1_cm_hash = poseidon_hash(
-                   c1_cm_x,
-                   c1_cm_y
-        );
-        constrain_instance(c1_cm_hash);
-        
-        # root of path to burnt coin commitment at given pos
-        root = merkle_root(c1_cm_pos, c1_cm_path, c1_cm_hash);
-        constrain_instance(root);
-        
-        # root of path at c1_sk_pos
-        root_sk = merkle_root(c1_sk_pos, c1_sk_path, c1_sk);
-        constrain_instance(root_sk);
-        
-        # coin (1) sn/nullifier
-        sn = poseidon_hash(
-           PREFIX_SN,
-           c1_sk_root,
-           c1_rho,
-           ZERO
-        );
-        constrain_instance(sn);
-}

+ 78 - 0
src/contract/money/proof/lead_burn_v1.zk

@@ -0,0 +1,78 @@
+constant "Lead_Burn_V1" {
+	EcFixedPointShort VALUE_COMMIT_VALUE,
+	EcFixedPoint VALUE_COMMIT_RANDOM,
+	EcFixedPointBase NULLIFIER_K,
+}
+
+contract "Lead_Burn_V1" {
+	MerklePath c1_cm_path,
+	Uint32 c1_cm_pos,
+	Uint32 c1_sk_pos,
+	Base c1_sk,
+	Base c1_sk_root,
+	MerklePath c1_sk_path,
+	Base c1_tau,
+	Base c1_rho,
+	Scalar c1_opening,
+	Base value,
+	Scalar value_blind,
+}
+
+circuit "Lead_Burn_V1" {
+	ZERO = witness_base(0);
+	PREFIX_CM = witness_base(4);
+	PREFIX_PK = witness_base(5);
+	PREFIX_SN = witness_base(6);
+
+	# value commitment
+	# necessary anonymously validading value state transition
+	vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
+	vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
+	value_commit = ec_add(vcv, vcr);
+	constrain_instance(ec_get_x(value_commit));
+	constrain_instance(ec_get_y(value_commit));
+
+	# coin (1) pk
+	pk = poseidon_hash(
+		PREFIX_PK,
+		c1_sk_root,
+		c1_tau,
+		ZERO
+	);
+	constrain_instance(pk);
+
+	# coin (1) cm/commitment
+	c1_cm_msg = poseidon_hash(
+		PREFIX_CM,
+		pk,
+		value,
+		c1_rho
+	);
+	c1_cm_v = ec_mul_base(c1_cm_msg, NULLIFIER_K);
+	c1_cm_r = ec_mul(c1_opening, VALUE_COMMIT_RANDOM);
+	c1_cm = ec_add(c1_cm_v, c1_cm_r);
+	c1_cm_x = ec_get_x(c1_cm);
+	c1_cm_y = ec_get_y(c1_cm);
+	c1_cm_hash = poseidon_hash(
+		c1_cm_x,
+		c1_cm_y
+	);
+	constrain_instance(c1_cm_hash);
+
+	# root of path to burnt coin commitment at given pos
+	root = merkle_root(c1_cm_pos, c1_cm_path, c1_cm_hash);
+	constrain_instance(root);
+
+	# root of path at c1_sk_pos
+	root_sk = merkle_root(c1_sk_pos, c1_sk_path, c1_sk);
+	constrain_instance(root_sk);
+
+	# coin (1) sn/nullifier
+	sn = poseidon_hash(
+		PREFIX_SN,
+		c1_sk_root,
+		c1_rho,
+		ZERO
+	);
+	constrain_instance(sn);
+}

+ 0 - 43
src/contract/money/proof/lead_mint.zk

@@ -1,43 +0,0 @@
-constant "LeadMint" {
-         EcFixedPointShort VALUE_COMMIT_VALUE,
-         EcFixedPoint VALUE_COMMIT_RANDOM,
-         EcFixedPointBase NULLIFIER_K,
-}
-
-contract "LeadMint" {
-         Base c1_sk,
-         Base c1_sk_root,
-         Base c1_tau,
-         Base c1_rho,
-         Scalar c1_opening,
-         Base value,
-         Scalar value_blind,
-}
-
-circuit "LeadMint" {
-        ZERO = witness_base(0);
-        PREFIX_CM = witness_base(4);
-        PREFIX_PK = witness_base(5);
-
-        # value commitment
-        # necessary anonymously validading value state transition
-	vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
-	vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
-	value_commit = ec_add(vcv, vcr);
-	constrain_instance(ec_get_x(value_commit));
-	constrain_instance(ec_get_y(value_commit));
-        
-        # coin (1) pk
-        pk = poseidon_hash(PREFIX_PK, c1_sk_root, c1_tau, ZERO);
-        constrain_instance(pk);
-        
-        # coin (1) cm/commitment
-        c1_cm_msg = poseidon_hash(PREFIX_CM, pk, value, c1_rho);
-        c1_cm_v = ec_mul_base(c1_cm_msg, NULLIFIER_K);
-        c1_cm_r = ec_mul(c1_opening, VALUE_COMMIT_RANDOM);
-        c1_cm = ec_add(c1_cm_v, c1_cm_r);
-        c1_cm_x = ec_get_x(c1_cm);
-        c1_cm_y = ec_get_y(c1_cm);
-        c1_cm_hash = poseidon_hash(c1_cm_x, c1_cm_y);
-        constrain_instance(c1_cm_hash);
-}

+ 43 - 0
src/contract/money/proof/lead_mint_v1.zk

@@ -0,0 +1,43 @@
+constant "Lead_Mint_V1" {
+	EcFixedPointShort VALUE_COMMIT_VALUE,
+	EcFixedPoint VALUE_COMMIT_RANDOM,
+	EcFixedPointBase NULLIFIER_K,
+}
+
+contract "Lead_Mint_V1" {
+	Base c1_sk,
+	Base c1_sk_root,
+	Base c1_tau,
+	Base c1_rho,
+	Scalar c1_opening,
+	Base value,
+	Scalar value_blind,
+}
+
+circuit "Lead_Mint_V1" {
+	ZERO = witness_base(0);
+	PREFIX_CM = witness_base(4);
+	PREFIX_PK = witness_base(5);
+
+	# value commitment
+	# necessary anonymously validading value state transition
+	vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
+	vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
+	value_commit = ec_add(vcv, vcr);
+	constrain_instance(ec_get_x(value_commit));
+	constrain_instance(ec_get_y(value_commit));
+
+	# coin (1) pk
+	pk = poseidon_hash(PREFIX_PK, c1_sk_root, c1_tau, ZERO);
+	constrain_instance(pk);
+
+	# coin (1) cm/commitment
+	c1_cm_msg = poseidon_hash(PREFIX_CM, pk, value, c1_rho);
+	c1_cm_v = ec_mul_base(c1_cm_msg, NULLIFIER_K);
+	c1_cm_r = ec_mul(c1_opening, VALUE_COMMIT_RANDOM);
+	c1_cm = ec_add(c1_cm_v, c1_cm_r);
+	c1_cm_x = ec_get_x(c1_cm);
+	c1_cm_y = ec_get_y(c1_cm);
+	c1_cm_hash = poseidon_hash(c1_cm_x, c1_cm_y);
+	constrain_instance(c1_cm_hash);
+}

+ 48 - 36
src/contract/money/src/lib.rs

@@ -20,6 +20,7 @@
 use darkfi_sdk::{
     crypto::{
         pedersen::{pedersen_commitment_base, pedersen_commitment_u64},
+        token_id::DARK_TOKEN_ID,
         Coin, ContractId, MerkleNode, MerkleTree, PublicKey,
     },
     db::{db_contains_key, db_get, db_init, db_lookup, db_set, SMART_CONTRACT_ZKAS_DB_NAME},
@@ -107,11 +108,10 @@ pub const MONEY_CONTRACT_ZKAS_MINT_NS_V1: &str = "Mint_V1";
 pub const MONEY_CONTRACT_ZKAS_BURN_NS_V1: &str = "Burn_V1";
 /// zkas token mint contract namespace
 pub const MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1: &str = "TokenMint_V1";
-
-/// zkas lead  mint contract namespace
-pub const MONEY_CONTRACT_ZKAS_LEAD_MINT_NS: &str = "Lead_Mint";
-/// zkas lead burn contract namespace
-pub const MONEY_CONTRACT_ZKAS_LEAD_BURN_NS: &str = "Lead_Burn";
+/// zkas staking coin mint contract namespace
+pub const MONEY_CONTRACT_ZKAS_LEAD_MINT_NS_V1: &str = "Lead_Mint_V1";
+/// zkas staking coin burn contract namespace
+pub const MONEY_CONTRACT_ZKAS_LEAD_BURN_NS_V1: &str = "Lead_Burn_V1";
 
 /// This function runs when the contract is (re)deployed and initialized.
 #[cfg(not(feature = "no-entrypoint"))]
@@ -127,13 +127,14 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
         Ok(v) => v,
         Err(_) => db_init(cid, SMART_CONTRACT_ZKAS_DB_NAME)?,
     };
+
     let mint_v1_bincode = include_bytes!("../proof/mint_v1.zk.bin");
     let burn_v1_bincode = include_bytes!("../proof/burn_v1.zk.bin");
 
     let token_mint_v1_bincode = include_bytes!("../proof/token_mint_v1.zk.bin");
 
-    let mint_lead_bincode = include_bytes!("../proof/lead_mint.zk.bin");
-    let burn_lead_bincode = include_bytes!("../proof/lead_burn.zk.bin");
+    let lead_mint_v1_bincode = include_bytes!("../proof/lead_mint_v1.zk.bin");
+    let lead_burn_v1_bincode = include_bytes!("../proof/lead_burn_v1.zk.bin");
 
     /* TODO: Do I really want to make zkas a dependency? Yeah, in the future.
        For now we take anything.
@@ -146,42 +147,37 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
     db_set(zkas_db, &serialize(&mint_namespace), &mint_bincode[..])?;
     db_set(zkas_db, &serialize(&burn_namespace), &burn_bincode[..])?;
     */
+
     db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_MINT_NS_V1), &mint_v1_bincode[..])?;
     db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_BURN_NS_V1), &burn_v1_bincode[..])?;
     db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1), &token_mint_v1_bincode[..])?;
-
-    db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_LEAD_MINT_NS), &mint_lead_bincode[..])?;
-    db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_LEAD_BURN_NS), &burn_lead_bincode[..])?;
+    db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_LEAD_MINT_NS_V1), &lead_mint_v1_bincode[..])?;
+    db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_LEAD_BURN_NS_V1), &lead_burn_v1_bincode[..])?;
 
     // Set up a database tree to hold Merkle roots
-    let _ = match db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE) {
-        Ok(v) => v,
-        Err(_) => db_init(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?,
-    };
+    if db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE).is_err() {
+        db_init(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
+    }
 
     // Set up a database tree to hold nullifiers
-    let _ = match db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE) {
-        Ok(v) => v,
-        Err(_) => db_init(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?,
-    };
+    if db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE).is_err() {
+        db_init(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
+    }
 
     // Set up a database tree to hold the set of fixed-supply tokens
-    let _ = match db_lookup(cid, MONEY_CONTRACT_FIXED_SUPPLY_TREE) {
-        Ok(v) => v,
-        Err(_) => db_init(cid, MONEY_CONTRACT_FIXED_SUPPLY_TREE)?,
-    };
+    if db_lookup(cid, MONEY_CONTRACT_FIXED_SUPPLY_TREE).is_err() {
+        db_init(cid, MONEY_CONTRACT_FIXED_SUPPLY_TREE)?;
+    }
 
     // Set up a database tree to hold lead Merkle roots
-    let _ = match db_lookup(cid, MONEY_CONTRACT_LEAD_COIN_ROOTS_TREE) {
-        Ok(v) => v,
-        Err(_) => db_init(cid, MONEY_CONTRACT_LEAD_COIN_ROOTS_TREE)?,
-    };
+    if db_lookup(cid, MONEY_CONTRACT_LEAD_COIN_ROOTS_TREE).is_err() {
+        db_init(cid, MONEY_CONTRACT_LEAD_COIN_ROOTS_TREE)?;
+    }
 
     // Set up a database tree to hold nullifiers
-    let _ = match db_lookup(cid, MONEY_CONTRACT_LEAD_NULLIFIERS_TREE) {
-        Ok(v) => v,
-        Err(_) => db_init(cid, MONEY_CONTRACT_LEAD_NULLIFIERS_TREE)?,
-    };
+    if db_lookup(cid, MONEY_CONTRACT_LEAD_NULLIFIERS_TREE).is_err() {
+        db_init(cid, MONEY_CONTRACT_LEAD_NULLIFIERS_TREE)?;
+    }
 
     // Set up a database tree for arbitrary data
     let info_db = match db_lookup(cid, MONEY_CONTRACT_INFO_TREE) {
@@ -256,7 +252,6 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
                 zk_public_values.push((
                     MONEY_CONTRACT_ZKAS_MINT_NS_V1.to_string(),
                     vec![
-                        //output.coin.inner(),
                         output.coin,
                         *value_coords.x(),
                         *value_coords.y(),
@@ -272,7 +267,9 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
 
             // Using this, we pass the above data to the host.
             set_return_data(&metadata)?;
+            Ok(())
         }
+
         MoneyFunction::Stake => {
             let params: MoneyStakeParams = deserialize(&self_.data[1..])?;
 
@@ -306,7 +303,7 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
                 let value_coords = output.value_commit.to_affine().coordinates().unwrap();
 
                 zk_public_values.push((
-                    MONEY_CONTRACT_ZKAS_LEAD_MINT_NS.to_string(),
+                    MONEY_CONTRACT_ZKAS_LEAD_MINT_NS_V1.to_string(),
                     vec![
                         *value_coords.x(),
                         *value_coords.y(),
@@ -322,7 +319,9 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
 
             // Using this, we pass the above data to the host.
             set_return_data(&metadata)?;
+            Ok(())
         }
+
         MoneyFunction::Unstake => {
             let params: MoneyUnstakeParams = deserialize(&self_.data[1..])?;
 
@@ -331,7 +330,7 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
             for input in &params.inputs {
                 let value_coords = input.value_commit.to_affine().coordinates().unwrap();
                 zk_public_values.push((
-                    MONEY_CONTRACT_ZKAS_LEAD_BURN_NS.to_string(),
+                    MONEY_CONTRACT_ZKAS_LEAD_BURN_NS_V1.to_string(),
                     vec![
                         *value_coords.x(),
                         *value_coords.y(),
@@ -364,14 +363,13 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
 
             // Using this, we pass the above data to the host.
             set_return_data(&metadata)?;
+            Ok(())
         }
         MoneyFunction::Mint => {
             msg!("[Mint] Entered match arm");
             unimplemented!();
         }
-    };
-
-    Ok(())
+    }
 }
 
 /// This function verifies a state transition and produces an
@@ -579,6 +577,13 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
 
             assert!(params.inputs.len() == params.outputs.len());
 
+            // Verify token commitment
+            let tokcom = pedersen_commitment_base(DARK_TOKEN_ID.inner(), params.token_blind);
+            if params.inputs.iter().any(|input| input.token_commit != tokcom) {
+                msg!("[Stake] Error: Tried to stake non-native token. Unable to proceed");
+                return Err(ContractError::Custom(26))
+            }
+
             let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_LEAD_NULLIFIERS_TREE)?;
             let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_LEAD_COIN_ROOTS_TREE)?;
 
@@ -644,6 +649,13 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
 
             assert!(params.inputs.len() == params.outputs.len());
 
+            // Verify token commitment
+            let tokcom = pedersen_commitment_base(DARK_TOKEN_ID.inner(), params.token_blind);
+            if params.outputs.iter().any(|output| output.token_commit != tokcom) {
+                msg!("[Stake] Error: Tried to unstake non-native token. Unable to proceed");
+                return Err(ContractError::Custom(26))
+            }
+
             let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_LEAD_NULLIFIERS_TREE)?;
             let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_LEAD_COIN_ROOTS_TREE)?;
             //let sk_roots_db = db_lookup(cid, MONEY_CONTRACT_LEAD_SK_ROOTS_TREE)?;

+ 4 - 0
src/contract/money/src/state.rs

@@ -32,6 +32,8 @@ pub struct MoneyStakeParams {
     pub inputs: Vec<Input>,
     /// Anonymous outputs for staking
     pub outputs: Vec<StakedOutput>,
+    /// Token blind to reveal token ID
+    pub token_blind: ValueBlind,
 }
 
 /// Inputs and outputs for unstaking coins
@@ -41,6 +43,8 @@ pub struct MoneyUnstakeParams {
     pub inputs: Vec<StakedInput>,
     /// Anonymous outputs
     pub outputs: Vec<Output>,
+    /// Token blind to reveal token ID
+    pub token_blind: ValueBlind,
 }
 
 /// Staked anonymous input