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

tx: major bugfix, do not reuse previous output value blinds. that will produce the same value_commit as the previous output making them linkable.

narodnik 4 лет назад
Родитель
Сommit
51c1e09415
4 измененных файлов с 27 добавлено и 4 удалено
  1. 4 0
      Cargo.lock
  2. 6 0
      src/error.rs
  3. 7 4
      src/tx/builder.rs
  4. 10 0
      src/tx/mod.rs

+ 4 - 0
Cargo.lock

@@ -1157,8 +1157,12 @@ dependencies = [
  "darkfi",
  "easy-parallel",
  "futures",
+ "halo2_gadgets",
+ "incrementalmerkletree",
  "log",
  "num_cpus",
+ "pasta_curves",
+ "rand",
  "serde_json",
  "simplelog",
  "smol",

+ 6 - 0
src/error.rs

@@ -324,6 +324,12 @@ pub enum Error {
 /// Transaction verification errors
 #[derive(Debug, Clone, thiserror::Error)]
 pub enum VerifyFailed {
+    #[error("Transaction has no inputs")]
+    LackingInputs,
+
+    #[error("Transaction has no outputs")]
+    LackingOutputs,
+
     #[error("Invalid cashier/faucet public key for clear input {0}")]
     InvalidCashierOrFaucetKey(usize),
 

+ 7 - 4
src/tx/builder.rs

@@ -69,6 +69,8 @@ impl TransactionBuilder {
     }
 
     pub fn build(self, mint_pk: &ProvingKey, burn_pk: &ProvingKey) -> Result<Transaction> {
+        assert!(self.clear_inputs.len() + self.inputs.len() > 0);
+
         let mut clear_inputs = vec![];
         let token_blind = DrkValueBlind::random(&mut OsRng);
         for input in &self.clear_inputs {
@@ -89,9 +91,8 @@ impl TransactionBuilder {
         let mut input_blinds = vec![];
         let mut signature_secrets = vec![];
         for input in self.inputs {
-            // FIXME: BUG - looks like we are reusing the value_blind from the output
-            // This must be a completely new random value or the value_commit will be the same.
-            input_blinds.push(input.note.value_blind);
+            let value_blind = DrkValueBlind::random(&mut OsRng);
+            input_blinds.push(value_blind);
 
             let signature_secret = SecretKey::random(&mut OsRng);
 
@@ -99,7 +100,7 @@ impl TransactionBuilder {
                 burn_pk,
                 input.note.value,
                 input.note.token_id,
-                input.note.value_blind,
+                value_blind,
                 token_blind,
                 input.note.serial,
                 input.note.coin_blind,
@@ -118,6 +119,8 @@ impl TransactionBuilder {
 
         let mut outputs = vec![];
         let mut output_blinds = vec![];
+        // This value_blind calc assumes there will always be at least a single output
+        assert!(self.outputs.len() > 0);
 
         for (i, output) in self.outputs.iter().enumerate() {
             let value_blind = if i == self.outputs.len() - 1 {

+ 10 - 0
src/tx/mod.rs

@@ -77,6 +77,16 @@ pub struct TransactionOutput {
 impl Transaction {
     /// Verify the transaction
     pub fn verify(&self, mint_vk: &VerifyingKey, burn_vk: &VerifyingKey) -> VerifyResult<()> {
+        // Transaction must have minimum 1 clear or anon input, and 1 output
+        if self.clear_inputs.len() + self.inputs.len() == 0 {
+            error!("tx::verify(): Missing inputs");
+            return Err(VerifyFailed::LackingInputs)
+        }
+        if self.outputs.len() == 0 {
+            error!("tx::verify(): Missing outputs");
+            return Err(VerifyFailed::LackingOutputs)
+        }
+
         // Accumulator for the value commitments
         let mut valcom_total = DrkValueCommit::identity();