Răsfoiți Sursa

cashu-sdk/mint: improve: check proofs are unique `melt`/`split`

thesimplekid 1 an în urmă
părinte
comite
9ddd36fc19
2 a modificat fișierele cu 25 adăugiri și 9 ștergeri
  1. 22 9
      crates/cashu-sdk/src/mint.rs
  2. 3 0
      crates/cashu/src/error.rs

+ 22 - 9
crates/cashu-sdk/src/mint.rs

@@ -108,10 +108,17 @@ impl Mint {
             return Err(Error::Amount);
         }
 
-        let mut secrets = Vec::with_capacity(split_request.proofs.len());
-        for proof in &split_request.proofs {
-            secrets.push(self.verify_proof(proof)?);
-            self.spent_secrets.insert(proof.secret.clone());
+        let proof_count = split_request.proofs.len();
+
+        let secrets: HashSet<String> = split_request.proofs.into_iter().map(|p| p.secret).collect();
+
+        // Check that there are no duplicate proofs in request
+        if secrets.len().ne(&proof_count) {
+            return Err(Error::DuplicateProofs);
+        }
+
+        for secret in secrets {
+            self.spent_secrets.insert(secret);
         }
 
         match &split_request.amount {
@@ -146,7 +153,7 @@ impl Mint {
         }
     }
 
-    pub fn verify_proof(&self, proof: &Proof) -> Result<String, Error> {
+    pub fn verify_proof(&self, proof: &Proof) -> Result<(), Error> {
         if self.spent_secrets.contains(&proof.secret) {
             return Err(Error::TokenSpent);
         }
@@ -172,7 +179,7 @@ impl Mint {
             &proof.secret,
         )?;
 
-        Ok(proof.secret.clone())
+        Ok(())
     }
 
     pub fn check_spendable(
@@ -202,9 +209,15 @@ impl Mint {
             return Err(Error::Amount);
         }
 
-        let mut secrets = Vec::with_capacity(melt_request.proofs.len());
-        for proof in &melt_request.proofs {
-            secrets.push(self.verify_proof(proof)?);
+        let secrets: HashSet<&str> = melt_request
+            .proofs
+            .iter()
+            .map(|p| p.secret.as_str())
+            .collect();
+
+        // Ensure proofs are unique and not being double spent
+        if melt_request.proofs.len().ne(&secrets.len()) {
+            return Err(Error::DuplicateProofs);
         }
 
         Ok(())

+ 3 - 0
crates/cashu/src/error.rs

@@ -162,6 +162,8 @@ pub mod mint {
         EllipticError(k256::elliptic_curve::Error),
         TokenNotVerifed,
         InvoiceAmountUndefined,
+        /// Duplicate Proofs sent in request
+        DuplicateProofs,
         CustomError(String),
     }
 
@@ -177,6 +179,7 @@ pub mod mint {
                 Error::CustomError(err) => write!(f, "{}", err),
                 Error::TokenNotVerifed => write!(f, "Token Not Verified"),
                 Error::InvoiceAmountUndefined => write!(f, "Invoice without amount"),
+                Error::DuplicateProofs => write!(f, "Request has duplicate proofs"),
             }
         }
     }