Преглед на файлове

darkfi: extend mint/burn proofs with spend_hook and user_data

narodnik преди 4 години
родител
ревизия
0adf5bbe2b
променени са 4 файла, в които са добавени 154 реда и са изтрити 19 реда
  1. 15 3
      src/crypto/burn_proof.rs
  2. 17 3
      src/crypto/mint_proof.rs
  3. 79 7
      src/zk/circuit/burn_contract.rs
  4. 43 6
      src/zk/circuit/mint_contract.rs

+ 15 - 3
src/crypto/burn_proof.rs

@@ -62,11 +62,19 @@ impl BurnRevealedValues {
         let public_key = PublicKey::from_secret(secret);
         let public_key = PublicKey::from_secret(secret);
         let coords = public_key.0.to_affine().coordinates().unwrap();
         let coords = public_key.0.to_affine().coordinates().unwrap();
 
 
-        let messages =
-            [*coords.x(), *coords.y(), DrkValue::from(value), token_id, serial, coin_blind];
+        let messages = [
+            *coords.x(),
+            *coords.y(),
+            DrkValue::from(value),
+            token_id,
+            serial,
+            spend_hook,
+            user_data,
+            coin_blind,
+        ];
 
 
         let coin =
         let coin =
-            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<6>, 3, 2>::init()
+            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<8>, 3, 2>::init()
                 .hash(messages);
                 .hash(messages);
 
 
         let merkle_root = {
         let merkle_root = {
@@ -116,6 +124,7 @@ impl BurnRevealedValues {
             *token_coords.x(),
             *token_coords.x(),
             *token_coords.y(),
             *token_coords.y(),
             merkle_root,
             merkle_root,
+            user_data_enc,
             *sig_coords.x(),
             *sig_coords.x(),
             *sig_coords.y(),
             *sig_coords.y(),
         ]
         ]
@@ -169,6 +178,9 @@ pub fn create_burn_proof(
         token_blind: Value::known(token_blind),
         token_blind: Value::known(token_blind),
         leaf_pos: Value::known(leaf_position as u32),
         leaf_pos: Value::known(leaf_position as u32),
         merkle_path: Value::known(merkle_path.try_into().unwrap()),
         merkle_path: Value::known(merkle_path.try_into().unwrap()),
+        spend_hook: Value::known(spend_hook),
+        user_data: Value::known(user_data),
+        user_data_blind: Value::known(user_data_blind),
         sig_secret: Value::known(signature_secret.0),
         sig_secret: Value::known(signature_secret.0),
     };
     };
 
 

+ 17 - 3
src/crypto/mint_proof.rs

@@ -36,6 +36,8 @@ impl MintRevealedValues {
         value_blind: DrkValueBlind,
         value_blind: DrkValueBlind,
         token_blind: DrkValueBlind,
         token_blind: DrkValueBlind,
         serial: DrkSerial,
         serial: DrkSerial,
+        spend_hook: DrkSpendHook,
+        user_data: DrkUserData,
         coin_blind: DrkCoinBlind,
         coin_blind: DrkCoinBlind,
         public_key: PublicKey,
         public_key: PublicKey,
     ) -> Self {
     ) -> Self {
@@ -43,11 +45,19 @@ impl MintRevealedValues {
         let token_commit = pedersen_commitment_base(token_id, token_blind);
         let token_commit = pedersen_commitment_base(token_id, token_blind);
 
 
         let coords = public_key.0.to_affine().coordinates().unwrap();
         let coords = public_key.0.to_affine().coordinates().unwrap();
-        let messages =
-            [*coords.x(), *coords.y(), DrkValue::from(value), token_id, serial, coin_blind];
+        let messages = [
+            *coords.x(),
+            *coords.y(),
+            DrkValue::from(value),
+            token_id,
+            serial,
+            spend_hook,
+            user_data,
+            coin_blind,
+        ];
 
 
         let coin =
         let coin =
-            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<6>, 3, 2>::init()
+            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<8>, 3, 2>::init()
                 .hash(messages);
                 .hash(messages);
 
 
         MintRevealedValues { value_commit, token_commit, coin: Coin(coin) }
         MintRevealedValues { value_commit, token_commit, coin: Coin(coin) }
@@ -88,6 +98,8 @@ pub fn create_mint_proof(
         value_blind,
         value_blind,
         token_blind,
         token_blind,
         serial,
         serial,
+        spend_hook,
+        user_data,
         coin_blind,
         coin_blind,
         public_key,
         public_key,
     );
     );
@@ -101,6 +113,8 @@ pub fn create_mint_proof(
         token: Value::known(token_id),
         token: Value::known(token_id),
         serial: Value::known(serial),
         serial: Value::known(serial),
         coin_blind: Value::known(coin_blind),
         coin_blind: Value::known(coin_blind),
+        spend_hook: Value::known(spend_hook),
+        user_data: Value::known(user_data),
         value_blind: Value::known(value_blind),
         value_blind: Value::known(value_blind),
         token_blind: Value::known(token_blind),
         token_blind: Value::known(token_blind),
     };
     };

+ 79 - 7
src/zk/circuit/burn_contract.rs

@@ -93,8 +93,9 @@ const BURN_VALCOMY_OFFSET: usize = 2;
 const BURN_TOKCOMX_OFFSET: usize = 3;
 const BURN_TOKCOMX_OFFSET: usize = 3;
 const BURN_TOKCOMY_OFFSET: usize = 4;
 const BURN_TOKCOMY_OFFSET: usize = 4;
 const BURN_MERKLEROOT_OFFSET: usize = 5;
 const BURN_MERKLEROOT_OFFSET: usize = 5;
-const BURN_SIGKEYX_OFFSET: usize = 6;
-const BURN_SIGKEYY_OFFSET: usize = 7;
+const BURN_USERDATA_OFFSET: usize = 6;
+const BURN_SIGKEYX_OFFSET: usize = 7;
+const BURN_SIGKEYY_OFFSET: usize = 8;
 
 
 #[derive(Default, Debug)]
 #[derive(Default, Debug)]
 pub struct BurnContract {
 pub struct BurnContract {
@@ -107,6 +108,12 @@ pub struct BurnContract {
     pub token_blind: Value<pallas::Scalar>,
     pub token_blind: Value<pallas::Scalar>,
     pub leaf_pos: Value<u32>,
     pub leaf_pos: Value<u32>,
     pub merkle_path: Value<[MerkleNode; MERKLE_DEPTH_ORCHARD]>,
     pub merkle_path: Value<[MerkleNode; MERKLE_DEPTH_ORCHARD]>,
+    /// Allows composing this ZK proof to invoke other contracts
+    pub spend_hook: Value<pallas::Base>,
+    /// Data passed from this coin to the invoked contract
+    pub user_data: Value<pallas::Base>,
+    /// Blinding factor for the encrypted user_data
+    pub user_data_blind: Value<pallas::Base>,
     pub sig_secret: Value<pallas::Base>,
     pub sig_secret: Value<pallas::Base>,
 }
 }
 
 
@@ -257,6 +264,24 @@ impl Circuit<pallas::Base> for BurnContract {
             self.serial,
             self.serial,
         )?;
         )?;
 
 
+        let spend_hook = assign_free_advice(
+            layouter.namespace(|| "load spend_hook"),
+            config.advices[0],
+            self.spend_hook,
+        )?;
+
+        let user_data = assign_free_advice(
+            layouter.namespace(|| "load user_data"),
+            config.advices[0],
+            self.user_data,
+        )?;
+
+        let user_data_blind = assign_free_advice(
+            layouter.namespace(|| "load user_data_blind"),
+            config.advices[0],
+            self.user_data_blind,
+        )?;
+
         let hash = {
         let hash = {
             let poseidon_message = [secret_key.clone(), serial.clone()];
             let poseidon_message = [secret_key.clone(), serial.clone()];
 
 
@@ -310,13 +335,14 @@ impl Circuit<pallas::Base> for BurnContract {
         // Coin hash
         // Coin hash
         // =========
         // =========
         let coin = {
         let coin = {
-            let poseidon_message = [pub_x, pub_y, value, token, serial, coin_blind];
+            let poseidon_message =
+                [pub_x, pub_y, value, token, serial, spend_hook, user_data.clone(), coin_blind];
 
 
             let poseidon_hasher = PoseidonHash::<
             let poseidon_hasher = PoseidonHash::<
                 _,
                 _,
                 _,
                 _,
                 poseidon::P128Pow5T3,
                 poseidon::P128Pow5T3,
-                poseidon::ConstantLength<6>,
+                poseidon::ConstantLength<8>,
                 3,
                 3,
                 2,
                 2,
             >::init(
             >::init(
@@ -353,6 +379,33 @@ impl Circuit<pallas::Base> for BurnContract {
             BURN_MERKLEROOT_OFFSET,
             BURN_MERKLEROOT_OFFSET,
         )?;
         )?;
 
 
+        // ===========
+        // Export user_data
+        // ===========
+        let user_data_enc = {
+            let poseidon_message = [user_data, user_data_blind];
+
+            let poseidon_hasher = PoseidonHash::<
+                _,
+                _,
+                poseidon::P128Pow5T3,
+                poseidon::ConstantLength<2>,
+                3,
+                2,
+            >::init(
+                config.poseidon_chip(), layouter.namespace(|| "Poseidon init")
+            )?;
+
+            let poseidon_output =
+                poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
+
+            let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output;
+            poseidon_output
+        };
+
+        // Constrain the coin C
+        layouter.constrain_instance(user_data_enc.cell(), config.primary, BURN_USERDATA_OFFSET)?;
+
         // ================
         // ================
         // Value commitment
         // Value commitment
         // ================
         // ================
@@ -506,13 +559,24 @@ mod tests {
         let serial = pallas::Base::random(&mut OsRng);
         let serial = pallas::Base::random(&mut OsRng);
         let coin_blind = pallas::Base::random(&mut OsRng);
         let coin_blind = pallas::Base::random(&mut OsRng);
         let secret = SecretKey::random(&mut OsRng);
         let secret = SecretKey::random(&mut OsRng);
+        let spend_hook = pallas::Base::random(&mut OsRng);
+        let user_data = pallas::Base::random(&mut OsRng);
+        let user_data_blind = pallas::Base::random(&mut OsRng);
         let sig_secret = SecretKey::random(&mut OsRng);
         let sig_secret = SecretKey::random(&mut OsRng);
 
 
         let coin2 = {
         let coin2 = {
             let coords = PublicKey::from_secret(secret).0.to_affine().coordinates().unwrap();
             let coords = PublicKey::from_secret(secret).0.to_affine().coordinates().unwrap();
-            let msg =
-                [*coords.x(), *coords.y(), pallas::Base::from(value), token_id, serial, coin_blind];
-            poseidon::Hash::<_, P128Pow5T3, ConstantLength<6>, 3, 2>::init().hash(msg)
+            let msg = [
+                *coords.x(),
+                *coords.y(),
+                pallas::Base::from(value),
+                token_id,
+                serial,
+                spend_hook,
+                user_data,
+                coin_blind,
+            ];
+            poseidon::Hash::<_, P128Pow5T3, ConstantLength<8>, 3, 2>::init().hash(msg)
         };
         };
 
 
         let mut tree = BridgeTree::<MerkleNode, 32>::new(100);
         let mut tree = BridgeTree::<MerkleNode, 32>::new(100);
@@ -542,6 +606,10 @@ mod tests {
         let token_commit = pedersen_commitment_base(token_id, token_blind);
         let token_commit = pedersen_commitment_base(token_id, token_blind);
         let token_coords = token_commit.to_affine().coordinates().unwrap();
         let token_coords = token_commit.to_affine().coordinates().unwrap();
 
 
+        let user_data_enc = [user_data, user_data_blind];
+        let user_data_enc =
+            poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(user_data_enc);
+
         let sig_pubkey = PublicKey::from_secret(sig_secret);
         let sig_pubkey = PublicKey::from_secret(sig_secret);
         let sig_coords = sig_pubkey.0.to_affine().coordinates().unwrap();
         let sig_coords = sig_pubkey.0.to_affine().coordinates().unwrap();
 
 
@@ -552,6 +620,7 @@ mod tests {
             *token_coords.x(),
             *token_coords.x(),
             *token_coords.y(),
             *token_coords.y(),
             merkle_root.0,
             merkle_root.0,
+            user_data_enc,
             *sig_coords.x(),
             *sig_coords.x(),
             *sig_coords.y(),
             *sig_coords.y(),
         ];
         ];
@@ -566,6 +635,9 @@ mod tests {
             token_blind: Value::known(token_blind),
             token_blind: Value::known(token_blind),
             leaf_pos: Value::known(leaf_pos.try_into().unwrap()),
             leaf_pos: Value::known(leaf_pos.try_into().unwrap()),
             merkle_path: Value::known(merkle_path.try_into().unwrap()),
             merkle_path: Value::known(merkle_path.try_into().unwrap()),
+            spend_hook: Value::known(spend_hook),
+            user_data: Value::known(user_data),
+            user_data_blind: Value::known(user_data_blind),
             sig_secret: Value::known(sig_secret.0),
             sig_secret: Value::known(sig_secret.0),
         };
         };
 
 

+ 43 - 6
src/zk/circuit/mint_contract.rs

@@ -66,6 +66,10 @@ pub struct MintContract {
     pub serial: Value<pallas::Base>,
     pub serial: Value<pallas::Base>,
     /// Random blinding factor for coin
     /// Random blinding factor for coin
     pub coin_blind: Value<pallas::Base>,
     pub coin_blind: Value<pallas::Base>,
+    /// Allows composing this ZK proof to invoke other contracts
+    pub spend_hook: Value<pallas::Base>,
+    /// Data passed from this coin to the invoked contract
+    pub user_data: Value<pallas::Base>,
     /// Random blinding factor for value commitment
     /// Random blinding factor for value commitment
     pub value_blind: Value<pallas::Scalar>,
     pub value_blind: Value<pallas::Scalar>,
     /// Random blinding factor for the token ID
     /// Random blinding factor for the token ID
@@ -201,6 +205,18 @@ impl Circuit<pallas::Base> for MintContract {
             self.serial,
             self.serial,
         )?;
         )?;
 
 
+        let spend_hook = assign_free_advice(
+            layouter.namespace(|| "load spend_hook"),
+            config.advices[6],
+            self.spend_hook,
+        )?;
+
+        let user_data = assign_free_advice(
+            layouter.namespace(|| "load user_data"),
+            config.advices[6],
+            self.user_data,
+        )?;
+
         let coin_blind = assign_free_advice(
         let coin_blind = assign_free_advice(
             layouter.namespace(|| "load coin_blind"),
             layouter.namespace(|| "load coin_blind"),
             config.advices[6],
             config.advices[6],
@@ -211,13 +227,22 @@ impl Circuit<pallas::Base> for MintContract {
         // Coin hash
         // Coin hash
         // =========
         // =========
         let coin = {
         let coin = {
-            let poseidon_message = [pub_x, pub_y, value.clone(), token.clone(), serial, coin_blind];
+            let poseidon_message = [
+                pub_x,
+                pub_y,
+                value.clone(),
+                token.clone(),
+                serial,
+                spend_hook,
+                user_data,
+                coin_blind,
+            ];
 
 
             let poseidon_hasher = PoseidonHash::<
             let poseidon_hasher = PoseidonHash::<
                 _,
                 _,
                 _,
                 _,
                 poseidon::P128Pow5T3,
                 poseidon::P128Pow5T3,
-                poseidon::ConstantLength<6>,
+                poseidon::ConstantLength<8>,
                 3,
                 3,
                 2,
                 2,
             >::init(
             >::init(
@@ -361,10 +386,20 @@ mod tests {
         let coin_blind = pallas::Base::random(&mut OsRng);
         let coin_blind = pallas::Base::random(&mut OsRng);
         let public_key = PublicKey::random(&mut OsRng);
         let public_key = PublicKey::random(&mut OsRng);
         let coords = public_key.0.to_affine().coordinates().unwrap();
         let coords = public_key.0.to_affine().coordinates().unwrap();
-
-        let msg =
-            [*coords.x(), *coords.y(), pallas::Base::from(value), token_id, serial, coin_blind];
-        let coin = poseidon::Hash::<_, P128Pow5T3, ConstantLength<6>, 3, 2>::init().hash(msg);
+        let spend_hook = pallas::Base::random(&mut OsRng);
+        let user_data = pallas::Base::random(&mut OsRng);
+
+        let msg = [
+            *coords.x(),
+            *coords.y(),
+            pallas::Base::from(value),
+            token_id,
+            serial,
+            spend_hook,
+            user_data,
+            coin_blind,
+        ];
+        let coin = poseidon::Hash::<_, P128Pow5T3, ConstantLength<8>, 3, 2>::init().hash(msg);
 
 
         let value_commit = pedersen_commitment_u64(value, value_blind);
         let value_commit = pedersen_commitment_u64(value, value_blind);
         let value_coords = value_commit.to_affine().coordinates().unwrap();
         let value_coords = value_commit.to_affine().coordinates().unwrap();
@@ -382,6 +417,8 @@ mod tests {
             token: Value::known(token_id),
             token: Value::known(token_id),
             serial: Value::known(serial),
             serial: Value::known(serial),
             coin_blind: Value::known(coin_blind),
             coin_blind: Value::known(coin_blind),
+            spend_hook: Value::known(spend_hook),
+            user_data: Value::known(user_data),
             value_blind: Value::known(value_blind),
             value_blind: Value::known(value_blind),
             token_blind: Value::known(token_blind),
             token_blind: Value::known(token_blind),
         };
         };