Преглед изворни кода

feat: verify p2pk on blinded message

thesimplekid пре 1 година
родитељ
комит
1bc9ad3528
2 измењених фајлова са 104 додато и 79 уклоњено
  1. 2 4
      crates/cashu-sdk/src/wallet/mod.rs
  2. 102 75
      crates/cashu/src/nuts/nut11.rs

+ 2 - 4
crates/cashu-sdk/src/wallet/mod.rs

@@ -795,7 +795,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
 
                         for pubkey in pubkeys {
                             if let Some(signing) = pubkey_secret_key.get(&pubkey.to_string()) {
-                                proof.sign_p2pk_proof(signing.clone()).unwrap();
+                                proof.sign_p2pk(signing.clone()).unwrap();
                                 proof.verify_p2pk().unwrap();
                             }
                         }
@@ -812,9 +812,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
             if let Some(sigflag) = sig_flag {
                 if sigflag.eq(&SigFlag::SigAll) {
                     for blinded_message in &mut pre_swap.swap_request.outputs {
-                        blinded_message
-                            .sign_p2pk_blinded_message(signing_key.clone())
-                            .unwrap();
+                        blinded_message.sign_p2pk(signing_key.clone()).unwrap();
                     }
                 }
             }

+ 102 - 75
crates/cashu/src/nuts/nut11.rs

@@ -80,6 +80,76 @@ impl Proof {
             witness: Signatures::default(),
         }
     }
+
+    pub fn verify_p2pk(&self) -> Result<(), Error> {
+        if !self.secret.is_p2pk() {
+            return Err(Error::IncorrectSecretKind);
+        }
+
+        let secret: Secret = self.secret.clone().try_into()?;
+
+        let spending_conditions: P2PKConditions = secret.clone().try_into()?;
+
+        let mut valid_sigs = 0;
+
+        let msg = &self.secret.to_bytes();
+
+        for signature in &self.witness.signatures {
+            let mut pubkeys = spending_conditions.pubkeys.clone();
+            let data_key = VerifyingKey::from_str(&secret.secret_data.data)?;
+            pubkeys.push(data_key);
+            for v in &spending_conditions.pubkeys {
+                let sig = Signature::try_from(hex::decode(signature)?.as_slice())?;
+
+                if v.verify(msg, &sig).is_ok() {
+                    valid_sigs += 1;
+                } else {
+                    debug!(
+                        "Could not verify signature: {} on message: {}",
+                        hex::encode(sig.to_bytes()),
+                        self.secret.to_string()
+                    )
+                }
+            }
+        }
+
+        if valid_sigs.ge(&spending_conditions.num_sigs.unwrap_or(1)) {
+            return Ok(());
+        }
+
+        println!("{:?}", spending_conditions.refund_keys);
+
+        if let Some(locktime) = spending_conditions.locktime {
+            // If lock time has passed check if refund witness signature is valid
+            if locktime.lt(&unix_time()) && !spending_conditions.refund_keys.is_empty() {
+                for s in &self.witness.signatures {
+                    for v in &spending_conditions.refund_keys {
+                        let sig = Signature::try_from(hex::decode(s)?.as_slice())
+                            .map_err(|_| Error::InvalidSignature)?;
+
+                        // As long as there is one valid refund signature it can be spent
+                        if v.verify(msg, &sig).is_ok() {
+                            return Ok(());
+                        }
+                    }
+                }
+            }
+        }
+
+        Err(Error::SpendConditionsNotMet)
+    }
+
+    pub fn sign_p2pk(&mut self, secret_key: SigningKey) -> Result<(), Error> {
+        let msg_to_sign = &self.secret.to_bytes();
+
+        let signature = secret_key.sign(msg_to_sign);
+
+        self.witness
+            .signatures
+            .push(hex::encode(signature.to_bytes()));
+
+        Ok(())
+    }
 }
 
 impl hash::Hash for Proof {
@@ -129,8 +199,7 @@ impl BlindedMessage {
         }
     }
 
-    #[cfg(feature = "nut11")]
-    pub fn sign_p2pk_blinded_message(&mut self, secret_key: SigningKey) -> Result<(), Error> {
+    pub fn sign_p2pk(&mut self, secret_key: SigningKey) -> Result<(), Error> {
         let msg_to_sign = hex::decode(self.b.to_string())?;
 
         let signature = secret_key.sign(&msg_to_sign);
@@ -140,6 +209,36 @@ impl BlindedMessage {
             .push(hex::encode(signature.to_bytes()));
         Ok(())
     }
+
+    pub fn verify_p2pk(
+        &self,
+        pubkeys: &Vec<VerifyingKey>,
+        required_sigs: u64,
+    ) -> Result<(), Error> {
+        let mut valid_sigs = 0;
+        for signature in &self.witness.signatures {
+            for v in pubkeys {
+                let msg = &self.b.to_bytes();
+                let sig = Signature::try_from(hex::decode(signature)?.as_slice())?;
+
+                if v.verify(msg, &sig).is_ok() {
+                    valid_sigs += 1;
+                } else {
+                    debug!(
+                        "Could not verify signature: {} on message: {}",
+                        hex::encode(sig.to_bytes()),
+                        self.b.to_string()
+                    )
+                }
+            }
+        }
+
+        if valid_sigs.ge(&required_sigs) {
+            Ok(())
+        } else {
+            Err(Error::SpendConditionsNotMet)
+        }
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -307,78 +406,6 @@ impl TryFrom<Secret> for P2PKConditions {
     }
 }
 
-impl Proof {
-    pub fn verify_p2pk(&self) -> Result<(), Error> {
-        if !self.secret.is_p2pk() {
-            return Err(Error::IncorrectSecretKind);
-        }
-
-        let secret: Secret = self.secret.clone().try_into()?;
-
-        let spending_conditions: P2PKConditions = secret.clone().try_into()?;
-
-        let mut valid_sigs = 0;
-
-        let msg = &self.secret.to_bytes();
-
-        for signature in &self.witness.signatures {
-            let mut pubkeys = spending_conditions.pubkeys.clone();
-            let data_key = VerifyingKey::from_str(&secret.secret_data.data)?;
-            pubkeys.push(data_key);
-            for v in &spending_conditions.pubkeys {
-                let sig = Signature::try_from(hex::decode(signature)?.as_slice())?;
-
-                if v.verify(msg, &sig).is_ok() {
-                    valid_sigs += 1;
-                } else {
-                    debug!(
-                        "Could not verify signature: {} on message: {}",
-                        hex::encode(sig.to_bytes()),
-                        self.secret.to_string()
-                    )
-                }
-            }
-        }
-
-        if valid_sigs.ge(&spending_conditions.num_sigs.unwrap_or(1)) {
-            return Ok(());
-        }
-
-        println!("{:?}", spending_conditions.refund_keys);
-
-        if let Some(locktime) = spending_conditions.locktime {
-            // If lock time has passed check if refund witness signature is valid
-            if locktime.lt(&unix_time()) && !spending_conditions.refund_keys.is_empty() {
-                for s in &self.witness.signatures {
-                    for v in &spending_conditions.refund_keys {
-                        let sig = Signature::try_from(hex::decode(s)?.as_slice())
-                            .map_err(|_| Error::InvalidSignature)?;
-
-                        // As long as there is one valid refund signature it can be spent
-                        if v.verify(msg, &sig).is_ok() {
-                            return Ok(());
-                        }
-                    }
-                }
-            }
-        }
-
-        Err(Error::SpendConditionsNotMet)
-    }
-
-    pub fn sign_p2pk_proof(&mut self, secret_key: SigningKey) -> Result<(), Error> {
-        let msg_to_sign = &self.secret.to_bytes();
-
-        let signature = secret_key.sign(msg_to_sign);
-
-        self.witness
-            .signatures
-            .push(hex::encode(signature.to_bytes()));
-
-        Ok(())
-    }
-}
-
 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[serde(rename_all = "lowercase")]
 pub enum TagKind {
@@ -802,7 +829,7 @@ mod tests {
             witness: Signatures { signatures: vec![] },
         };
 
-        proof.sign_p2pk_proof(secret_key).unwrap();
+        proof.sign_p2pk(secret_key).unwrap();
 
         assert!(proof.verify_p2pk().is_ok());
     }