Эх сурвалжийг харах

Blind the asset_id and enforce asset matches among inputs and outputs.

Nym 5 жил өмнө
parent
commit
48beeeb94d

+ 12 - 0
proofs/mint.pism

@@ -11,6 +11,7 @@ contract mint_contract
     param value U64
     param asset_id U64
     param randomness_value Fr
+    param randomness_asset Fr
 
     param serial Fr
     param randomness_coin Fr
@@ -20,6 +21,7 @@ start
     u64_as_binary_le value param:value
     u64_as_binary_le asset_id param:asset_id
     fr_as_binary_le randomness_value param:randomness_value
+    fr_as_binary_le randomness_asset param:randomness_asset
     fr_as_binary_le serial param:serial
     fr_as_binary_le randomness_coin param:randomness_coin
 
@@ -35,6 +37,16 @@ start
     # emit cv
     emit_ec cv
 
+    # Make asset_id commitment
+    # A = a * G_VCV + r_a * G_VCR
+
+    ec_mul_const vca asset_id G_VCV
+    ec_mul_const rca randomness_asset G_VCR
+    ec_add ca vca rca
+    # emit ca
+    emit_ec ca
+
+
     # Make the coin
     # C = Hash(public_key, value, asset_id, serial, randomness_coin)
 

+ 11 - 0
proofs/spend.pism

@@ -13,6 +13,7 @@ contract spend_contract
     param value U64
     param asset_id U64
     param randomness_value Fr
+    param randomness_asset Fr
 
     param serial Fr
     param randomness_coin Fr
@@ -28,6 +29,7 @@ start
     u64_as_binary_le value param:value
     u64_as_binary_le asset_id param:asset_id
     fr_as_binary_le randomness_value param:randomness_value
+    fr_as_binary_le randomness_asset param:randomness_asset
 
     # Make value commitment
     # V = v * G_VCV + r * G_VCR
@@ -38,6 +40,15 @@ start
     # emit cv
     emit_ec cv
 
+    # Make asset_id commitment
+    # A = a * G_VCV + r * G_VCR
+
+    ec_mul_const vca asset_id G_VCV
+    ec_mul_const rca randomness_asset G_VCR
+    ec_add ca vca rca
+    # emit ca
+    emit_ec ca
+
     # Make the nullifier
     # N = Hash(secret, serial)
     fr_as_binary_le serial param:serial

+ 2 - 0
src/bin/mint-classic.rs

@@ -13,6 +13,7 @@ fn main() {
     let value = 110;
     let asset_id = 1;
     let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let randomness_asset: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
 
     let serial: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
     let randomness_coin: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
@@ -28,6 +29,7 @@ fn main() {
         value,
         asset_id,
         randomness_value,
+        randomness_asset,
         serial,
         randomness_coin,
         public,

+ 2 - 0
src/bin/spend-classic.rs

@@ -174,6 +174,7 @@ fn main() {
     let value = 110;
     let asset_id = 1;
     let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let randomness_asset: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
 
     let serial: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
     let randomness_coin: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
@@ -200,6 +201,7 @@ fn main() {
         value,
         asset_id,
         randomness_value,
+        randomness_asset,
         serial,
         randomness_coin,
         secret,

+ 29 - 1
src/circuit/mint_contract.rs

@@ -17,6 +17,7 @@ pub struct MintContract {
     pub value: Option<u64>,
     pub asset_id: Option<u64>,
     pub randomness_value: Option<jubjub::Fr>,
+    pub randomness_asset: Option<jubjub::Fr>,
     pub serial: Option<jubjub::Fr>,
     pub randomness_coin: Option<jubjub::Fr>,
     pub public: Option<jubjub::SubgroupPoint>,
@@ -34,7 +35,7 @@ impl Circuit<bls12_381::Scalar> for MintContract {
 
         // Line 19: u64_as_binary_le asset_id param:asset_id
         let asset_id = boolean::u64_into_boolean_vec_le(
-            cs.namespace(|| "Line 19: u64_as_binary_le value param:asset_id"),
+            cs.namespace(|| "Line 19: u64_as_binary_le asset_id param:asset_id"),
             self.asset_id,
         )?;
 
@@ -44,6 +45,12 @@ impl Circuit<bls12_381::Scalar> for MintContract {
             self.randomness_value,
         )?;
 
+        // Line 19: fr_as_binary_le randomness_asset param:randomness_asset
+        let randomness_asset = boolean::field_into_boolean_vec_le(
+            cs.namespace(|| "Line 19: fr_as_binary_le randomness_asset param:randomness_asset"),
+            self.randomness_asset,
+        )?;
+
         // Line 20: fr_as_binary_le serial param:serial
         let serial = boolean::field_into_boolean_vec_le(
             cs.namespace(|| "Line 20: fr_as_binary_le serial param:serial"),
@@ -85,6 +92,27 @@ impl Circuit<bls12_381::Scalar> for MintContract {
         // Line 33: emit_ec cv
         cv.inputize(cs.namespace(|| "Line 33: emit_ec cv"))?;
 
+        // Line 29: ec_mul_const vca asset_id G_VCV
+        let vca = ecc::fixed_base_multiplication(
+            cs.namespace(|| "Line 29: ec_mul_const vca asset_id G_VCV"),
+            &zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR,
+            &asset_id,
+        )?;
+
+        // Line 47: ec_mul_const rca randomness_asset G_VCR
+        let rca = ecc::fixed_base_multiplication(
+            cs.namespace(|| "Line 47: ec_mul_const rca randomness_asset G_VCR"),
+            &zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
+            &randomness_asset,
+        )?;
+
+        // Line 48: ec_add ca vca rca
+        let ca = vca.add(cs.namespace(|| "Line 48: ec_add ca vca rca"), &rca)?;
+
+        // Line 50: emit_ec ca
+        ca.inputize(cs.namespace(|| "Line 50: emit_ec ca"))?;
+
+
         // Line 39: alloc_binary preimage
         let mut preimage = vec![];
 

+ 28 - 0
src/circuit/spend_contract.rs

@@ -19,6 +19,7 @@ pub struct SpendContract {
     pub value: Option<u64>,
     pub asset_id: Option<u64>,
     pub randomness_value: Option<jubjub::Fr>,
+    pub randomness_asset: Option<jubjub::Fr>,
     pub serial: Option<jubjub::Fr>,
     pub randomness_coin: Option<jubjub::Fr>,
     pub secret: Option<jubjub::Fr>,
@@ -49,6 +50,12 @@ impl Circuit<bls12_381::Scalar> for SpendContract {
             self.randomness_value,
         )?;
 
+        // Line 41: fr_as_binary_le randomness_asset param:randomness_asset
+        let randomness_asset = boolean::field_into_boolean_vec_le(
+            cs.namespace(|| "Line 41: fr_as_binary_le randomness_asset param:randomness_asset"),
+            self.randomness_asset,
+        )?;
+
         // Line 46: ec_mul_const vcv value G_VCV
         let vcv = ecc::fixed_base_multiplication(
             cs.namespace(|| "Line 46: ec_mul_const vcv value G_VCV"),
@@ -69,6 +76,27 @@ impl Circuit<bls12_381::Scalar> for SpendContract {
         // Line 50: emit_ec cv
         cv.inputize(cs.namespace(|| "Line 50: emit_ec cv"))?;
 
+        // Line 46: ec_mul_const vca asset_id G_VCV
+        let vca = ecc::fixed_base_multiplication(
+            cs.namespace(|| "Line 46: ec_mul_const vca asset_id G_VCV"),
+            &zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR,
+            &asset_id,
+        )?;
+
+        // Line 47: ec_mul_const rca randomness_asset G_VCR
+        let rca = ecc::fixed_base_multiplication(
+            cs.namespace(|| "Line 47: ec_mul_const rca randomness_asset G_VCR"),
+            &zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
+            &randomness_asset,
+        )?;
+
+        // Line 48: ec_add ca vca rca
+        let ca = vca.add(cs.namespace(|| "Line 48: ec_add ca vca rca"), &rca)?;
+
+        // Line 50: emit_ec ca
+        ca.inputize(cs.namespace(|| "Line 50: emit_ec ca"))?;
+
+
         // Line 54: fr_as_binary_le serial param:serial
         let serial = boolean::field_into_boolean_vec_le(
             cs.namespace(|| "Line 54: fr_as_binary_le serial param:serial"),

+ 27 - 6
src/crypto/mint_proof.rs

@@ -13,6 +13,7 @@ use crate::serial::{Decodable, Encodable};
 
 pub struct MintRevealedValues {
     pub value_commit: jubjub::SubgroupPoint,
+    pub asset_commit: jubjub::SubgroupPoint,
     pub coin: [u8; 32],
 }
 
@@ -21,6 +22,7 @@ impl MintRevealedValues {
         value: u64,
         asset_id: u64,
         randomness_value: &jubjub::Fr,
+        randomness_asset: &jubjub::Fr,
         serial: &jubjub::Fr,
         randomness_coin: &jubjub::Fr,
         public: &jubjub::SubgroupPoint,
@@ -30,6 +32,11 @@ impl MintRevealedValues {
             + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
                 * randomness_value);
 
+        let asset_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
+            * jubjub::Fr::from(asset_id))
+            + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
+                * randomness_asset);
+
         let mut coin = [0; 32];
         coin.copy_from_slice(
             Blake2sParams::new()
@@ -45,11 +52,11 @@ impl MintRevealedValues {
                 .as_bytes(),
         );
 
-        MintRevealedValues { value_commit, coin }
+        MintRevealedValues { value_commit, asset_commit, coin }
     }
 
-    fn make_outputs(&self) -> [bls12_381::Scalar; 4] {
-        let mut public_input = [bls12_381::Scalar::zero(); 4];
+    fn make_outputs(&self) -> [bls12_381::Scalar; 6] {
+        let mut public_input = [bls12_381::Scalar::zero(); 6];
 
         {
             let result = jubjub::ExtendedPoint::from(self.value_commit);
@@ -61,6 +68,15 @@ impl MintRevealedValues {
             public_input[1] = v;
         }
 
+        {
+            let result = jubjub::ExtendedPoint::from(self.asset_commit);
+            let affine = result.to_affine();
+            let u = affine.get_u();
+            let v = affine.get_v();
+            public_input[2] = u;
+            public_input[3] = v;
+        }
+
         {
             // Pack the hash as inputs for proof verification.
             let hash = multipack::bytes_to_bits_le(&self.coin);
@@ -69,8 +85,8 @@ impl MintRevealedValues {
             // There are 2 chunks for a blake hash
             assert_eq!(hash.len(), 2);
 
-            public_input[2] = hash[0];
-            public_input[3] = hash[1];
+            public_input[4] = hash[0];
+            public_input[5] = hash[1];
         }
 
         public_input
@@ -81,6 +97,7 @@ impl Encodable for MintRevealedValues {
     fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
         let mut len = 0;
         len += self.value_commit.encode(&mut s)?;
+        len += self.asset_commit.encode(&mut s)?;
         len += self.coin.encode(&mut s)?;
         Ok(len)
     }
@@ -90,6 +107,7 @@ impl Decodable for MintRevealedValues {
     fn decode<D: io::Read>(mut d: D) -> Result<Self> {
         Ok(Self {
             value_commit: Decodable::decode(&mut d)?,
+            asset_commit: Decodable::decode(&mut d)?,
             coin: Decodable::decode(d)?,
         })
     }
@@ -103,6 +121,7 @@ pub fn setup_mint_prover() -> groth16::Parameters<Bls12> {
             value: None,
             asset_id: None,
             randomness_value: None,
+            randomness_asset: None,
             serial: None,
             randomness_coin: None,
             public: None,
@@ -118,17 +137,19 @@ pub fn create_mint_proof(
     value: u64,
     asset_id: u64,
     randomness_value: jubjub::Fr,
+    randomness_asset: jubjub::Fr,
     serial: jubjub::Fr,
     randomness_coin: jubjub::Fr,
     public: jubjub::SubgroupPoint,
 ) -> (groth16::Proof<Bls12>, MintRevealedValues) {
     let revealed =
-        MintRevealedValues::compute(value, asset_id, &randomness_value, &serial, &randomness_coin, &public);
+        MintRevealedValues::compute(value, asset_id, &randomness_value, &randomness_asset, &serial, &randomness_coin, &public);
 
     let c = MintContract {
         value: Some(value),
         asset_id: Some(asset_id),
         randomness_value: Some(randomness_value),
+        randomness_asset: Some(randomness_asset),
         serial: Some(serial),
         randomness_coin: Some(randomness_coin),
         public: Some(public),

+ 32 - 7
src/crypto/spend_proof.rs

@@ -16,6 +16,7 @@ use crate::serial::{Decodable, Encodable};
 
 pub struct SpendRevealedValues {
     pub value_commit: jubjub::SubgroupPoint,
+    pub asset_commit: jubjub::SubgroupPoint,
     pub nullifier: Nullifier,
     // This should not be here, we just have it for debugging
     //coin: [u8; 32],
@@ -28,6 +29,7 @@ impl SpendRevealedValues {
         value: u64,
         asset_id: u64,
         randomness_value: &jubjub::Fr,
+        randomness_asset: &jubjub::Fr,
         serial: &jubjub::Fr,
         randomness_coin: &jubjub::Fr,
         secret: &jubjub::Fr,
@@ -39,6 +41,11 @@ impl SpendRevealedValues {
             + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
                 * randomness_value);
 
+        let asset_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
+            * jubjub::Fr::from(asset_id))
+            + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
+                * randomness_asset);
+
         let mut nullifier = [0; 32];
         nullifier.copy_from_slice(
             Blake2sParams::new()
@@ -91,14 +98,15 @@ impl SpendRevealedValues {
 
         SpendRevealedValues {
             value_commit,
+            asset_commit,
             nullifier,
             merkle_root,
             signature_public,
         }
     }
 
-    fn make_outputs(&self) -> [bls12_381::Scalar; 7] {
-        let mut public_input = [bls12_381::Scalar::zero(); 7];
+    fn make_outputs(&self) -> [bls12_381::Scalar; 9] {
+        let mut public_input = [bls12_381::Scalar::zero(); 9];
 
         // CV
         {
@@ -111,6 +119,17 @@ impl SpendRevealedValues {
             public_input[1] = v;
         }
 
+        // CA
+        {
+            let result = jubjub::ExtendedPoint::from(self.asset_commit);
+            let affine = result.to_affine();
+            //let (u, v) = (affine.get_u(), affine.get_v());
+            let u = affine.get_u();
+            let v = affine.get_v();
+            public_input[2] = u;
+            public_input[3] = v;
+        }
+
         // NF
         {
             // Pack the hash as inputs for proof verification.
@@ -120,8 +139,8 @@ impl SpendRevealedValues {
             // There are 2 chunks for a blake hash
             assert_eq!(hash.len(), 2);
 
-            public_input[2] = hash[0];
-            public_input[3] = hash[1];
+            public_input[4] = hash[0];
+            public_input[5] = hash[1];
         }
 
         // Not revealed. We leave this code here for debug
@@ -138,7 +157,7 @@ impl SpendRevealedValues {
             public_input[5] = hash[1];
         }*/
 
-        public_input[4] = self.merkle_root.into();
+        public_input[6] = self.merkle_root.into();
 
         {
             let result = jubjub::ExtendedPoint::from(self.signature_public);
@@ -146,8 +165,8 @@ impl SpendRevealedValues {
             //let (u, v) = (affine.get_u(), affine.get_v());
             let u = affine.get_u();
             let v = affine.get_v();
-            public_input[5] = u;
-            public_input[6] = v;
+            public_input[7] = u;
+            public_input[8] = v;
         }
 
         public_input
@@ -158,6 +177,7 @@ impl Encodable for SpendRevealedValues {
     fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
         let mut len = 0;
         len += self.value_commit.encode(&mut s)?;
+        len += self.asset_commit.encode(&mut s)?;
         len += self.nullifier.encode(&mut s)?;
         len += self.merkle_root.encode(&mut s)?;
         len += self.signature_public.encode(s)?;
@@ -169,6 +189,7 @@ impl Decodable for SpendRevealedValues {
     fn decode<D: io::Read>(mut d: D) -> Result<Self> {
         Ok(Self {
             value_commit: Decodable::decode(&mut d)?,
+            asset_commit: Decodable::decode(&mut d)?,
             nullifier: Decodable::decode(&mut d)?,
             merkle_root: Decodable::decode(&mut d)?,
             signature_public: Decodable::decode(d)?,
@@ -184,6 +205,7 @@ pub fn setup_spend_prover() -> groth16::Parameters<Bls12> {
             value: None,
             asset_id: None,
             randomness_value: None,
+            randomness_asset: None,
             serial: None,
             randomness_coin: None,
             secret: None,
@@ -204,6 +226,7 @@ pub fn create_spend_proof(
     value: u64,
     asset_id: u64,
     randomness_value: jubjub::Fr,
+    randomness_asset: jubjub::Fr,
     serial: jubjub::Fr,
     randomness_coin: jubjub::Fr,
     secret: jubjub::Fr,
@@ -221,6 +244,7 @@ pub fn create_spend_proof(
         value: Some(value),
         asset_id: Some(asset_id),
         randomness_value: Some(randomness_value),
+        randomness_asset: Some(randomness_asset),
         serial: Some(serial),
         randomness_coin: Some(randomness_coin),
         secret: Some(secret),
@@ -239,6 +263,7 @@ pub fn create_spend_proof(
         value,
         asset_id,
         &randomness_value,
+        &randomness_asset,
         &serial,
         &randomness_coin,
         &secret,

+ 4 - 0
src/state.rs

@@ -34,6 +34,7 @@ pub enum VerifyFailed {
     ClearInputSignature(usize),
     InputSignature(usize),
     MissingFunds,
+    AssetMismatch,
 }
 
 impl std::error::Error for VerifyFailed {}
@@ -59,6 +60,9 @@ impl fmt::Display for VerifyFailed {
             VerifyFailed::MissingFunds => {
                 f.write_str("Money in does not match money out (value commits)")
             }
+            VerifyFailed::AssetMismatch => {
+                f.write_str("Assets don't match some inputs or outputs (asset commits)")
+            }
         }
     }
 }

+ 5 - 0
src/tx/builder.rs

@@ -66,6 +66,7 @@ impl TransactionBuilder {
         spend_params: &groth16::Parameters<Bls12>,
     ) -> Transaction {
         let mut clear_inputs = vec![];
+        let asset_commit_blind: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
         for input in &self.clear_inputs {
             let signature_public =
                 zcash_primitives::constants::SPENDING_KEY_GENERATOR * input.signature_secret;
@@ -75,6 +76,7 @@ impl TransactionBuilder {
                 value: input.value,
                 asset_id: input.asset_id,
                 valcom_blind,
+                asset_commit_blind,
                 signature_public,
             };
             clear_inputs.push(clear_input);
@@ -103,6 +105,7 @@ impl TransactionBuilder {
                 input.note.value,
                 input.note.asset_id,
                 input.note.valcom_blind,
+                asset_commit_blind,
                 input.note.serial,
                 input.note.coin_blind,
                 input.secret,
@@ -123,6 +126,7 @@ impl TransactionBuilder {
 
         let mut outputs = vec![];
         let mut output_blinds = vec![];
+
         for (i, output) in self.outputs.iter().enumerate() {
             let valcom_blind = if i == self.outputs.len() - 1 {
                 Self::compute_remainder_blind(&clear_inputs, &input_blinds, &output_blinds)
@@ -139,6 +143,7 @@ impl TransactionBuilder {
                 output.value,
                 output.asset_id,
                 valcom_blind.clone(),
+                asset_commit_blind.clone(),
                 serial.clone(),
                 coin_blind.clone(),
                 output.public.clone(),

+ 22 - 2
src/tx/mod.rs

@@ -31,6 +31,7 @@ pub struct TransactionClearInput {
     pub value: u64,
     pub asset_id: u64,
     pub valcom_blind: jubjub::Fr,
+    pub asset_commit_blind: jubjub::Fr,
     pub signature_public: jubjub::SubgroupPoint,
     pub signature: schnorr::Signature,
 }
@@ -56,13 +57,23 @@ impl Transaction {
         Ok(len)
     }
 
-    fn compute_value_commit(value: u64, blind: &jubjub::Fr) -> jubjub::SubgroupPoint {
+    fn compute_pedersen_commit(value: u64, blind: &jubjub::Fr) -> jubjub::SubgroupPoint {
         let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
             * jubjub::Fr::from(value))
             + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * blind);
         value_commit
     }
 
+    fn verify_asset_commitments(&self) -> bool {
+        assert_ne!(self.outputs.len(), 0);
+        let asset_commit_value = self.outputs[0].revealed.asset_commit;
+
+        let mut failed = self.inputs.iter().any(|input| input.revealed.asset_commit != asset_commit_value);
+        failed = failed || self.outputs.iter().any(|output| output.revealed.asset_commit != asset_commit_value);
+        failed = failed || self.clear_inputs.iter().any(|input| Self::compute_pedersen_commit(input.asset_id, &input.asset_commit_blind) != asset_commit_value);
+        !failed
+    }
+
     pub fn verify(
         &self,
         mint_pvk: &groth16::PreparedVerifyingKey<Bls12>,
@@ -70,7 +81,7 @@ impl Transaction {
     ) -> state::VerifyResult<()> {
         let mut valcom_total = jubjub::SubgroupPoint::identity();
         for input in &self.clear_inputs {
-            valcom_total += Self::compute_value_commit(input.value, &input.valcom_blind);
+            valcom_total += Self::compute_pedersen_commit(input.value, &input.valcom_blind);
         }
         for (i, input) in self.inputs.iter().enumerate() {
             if !verify_spend_proof(spend_pvk, &input.spend_proof, &input.revealed) {
@@ -89,6 +100,11 @@ impl Transaction {
             return Err(state::VerifyFailed::MissingFunds);
         }
 
+        // Verify asset commitments match
+        if !self.verify_asset_commitments() {
+            return Err(state::VerifyFailed::AssetMismatch);
+        }
+
         // Verify signatures
         let mut unsigned_tx_data = vec![];
         self.encode_without_signature(&mut unsigned_tx_data)
@@ -116,6 +132,7 @@ impl TransactionClearInput {
             value: partial.value,
             asset_id: partial.asset_id,
             valcom_blind: partial.valcom_blind,
+            asset_commit_blind: partial.asset_commit_blind,
             signature_public: partial.signature_public,
             signature,
         }
@@ -126,6 +143,7 @@ impl TransactionClearInput {
         len += self.value.encode(&mut s)?;
         len += self.asset_id.encode(&mut s)?;
         len += self.valcom_blind.encode(&mut s)?;
+        len += self.asset_commit_blind.encode(&mut s)?;
         len += self.signature_public.encode(s)?;
         Ok(len)
     }
@@ -174,6 +192,7 @@ impl Encodable for TransactionClearInput {
         len += self.value.encode(&mut s)?;
         len += self.asset_id.encode(&mut s)?;
         len += self.valcom_blind.encode(&mut s)?;
+        len += self.asset_commit_blind.encode(&mut s)?;
         len += self.signature_public.encode(&mut s)?;
         len += self.signature.encode(s)?;
         Ok(len)
@@ -186,6 +205,7 @@ impl Decodable for TransactionClearInput {
             value: Decodable::decode(&mut d)?,
             asset_id: Decodable::decode(&mut d)?,
             valcom_blind: Decodable::decode(&mut d)?,
+            asset_commit_blind: Decodable::decode(&mut d)?,
             signature_public: Decodable::decode(&mut d)?,
             signature: Decodable::decode(d)?,
         })

+ 3 - 0
src/tx/partial.rs

@@ -18,6 +18,7 @@ pub struct PartialTransactionClearInput {
     pub value: u64,
     pub asset_id: u64,
     pub valcom_blind: jubjub::Fr,
+    pub asset_commit_blind: jubjub::Fr,
     pub signature_public: jubjub::SubgroupPoint,
 }
 
@@ -52,6 +53,7 @@ impl Encodable for PartialTransactionClearInput {
         len += self.value.encode(&mut s)?;
         len += self.asset_id.encode(&mut s)?;
         len += self.valcom_blind.encode(&mut s)?;
+        len += self.asset_commit_blind.encode(&mut s)?;
         len += self.signature_public.encode(&mut s)?;
         Ok(len)
     }
@@ -62,6 +64,7 @@ impl Decodable for PartialTransactionClearInput {
             value: Decodable::decode(&mut d)?,
             asset_id: Decodable::decode(&mut d)?,
             valcom_blind: Decodable::decode(&mut d)?,
+            asset_commit_blind: Decodable::decode(&mut d)?,
             signature_public: Decodable::decode(&mut d)?,
         })
     }