Sfoglia il codice sorgente

refactor: add keyset_id to blinded_message
stop mint from signing if keyset in
blinded_message is not the active keyset

thesimplekid 1 anno fa
parent
commit
989035e12e

+ 3 - 3
bindings/cashu-ffi/src/cashu.udl

@@ -50,7 +50,7 @@ interface SecretKey {
 };
 
 interface BlindedMessage {
-	constructor(Amount amount, PublicKey b);
+	constructor(Id keyset_id, Amount amount, PublicKey b);
 	Amount amount();
 	PublicKey b();	
 };
@@ -100,9 +100,9 @@ interface Token {
 
 interface BlindedMessages {
     [Throws=CashuError, Name=random]
-	constructor(Amount amount);
+	constructor(Id keyset_id, Amount amount);
     [Throws=CashuError, Name=blank]
-	constructor(Amount fee_reserve);
+	constructor(Id keyset_id, Amount amount);
 	sequence<BlindedMessage> blinded_messages();
 	sequence<Secret> secrets();
 	sequence<SecretKey> rs();

+ 3 - 2
bindings/cashu-ffi/src/nuts/nut00/blinded_message.rs

@@ -4,7 +4,7 @@ use std::sync::Arc;
 use cashu::nuts::BlindedMessage as BlindedMessageSdk;
 
 use crate::nuts::nut01::public_key::PublicKey;
-use crate::Amount;
+use crate::{Amount, Id};
 
 pub struct BlindedMessage {
     inner: BlindedMessageSdk,
@@ -18,9 +18,10 @@ impl Deref for BlindedMessage {
 }
 
 impl BlindedMessage {
-    pub fn new(amount: Arc<Amount>, b: Arc<PublicKey>) -> Self {
+    pub fn new(keyset_id: Arc<Id>, amount: Arc<Amount>, b: Arc<PublicKey>) -> Self {
         Self {
             inner: BlindedMessageSdk {
+                keyset_id: *keyset_id.as_ref().deref(),
                 amount: *amount.as_ref().deref(),
                 b: b.as_ref().into(),
             },

+ 11 - 5
bindings/cashu-ffi/src/nuts/nut00/blinded_messages.rs

@@ -4,7 +4,7 @@ use std::sync::Arc;
 use cashu::nuts::nut00::wallet::BlindedMessages as BlindedMessagesSdk;
 
 use crate::error::Result;
-use crate::{Amount, BlindedMessage, Secret, SecretKey};
+use crate::{Amount, BlindedMessage, Id, Secret, SecretKey};
 
 pub struct BlindedMessages {
     inner: BlindedMessagesSdk,
@@ -18,15 +18,21 @@ impl Deref for BlindedMessages {
 }
 
 impl BlindedMessages {
-    pub fn random(amount: Arc<Amount>) -> Result<Self> {
+    pub fn random(keyset_id: Arc<Id>, amount: Arc<Amount>) -> Result<Self> {
         Ok(Self {
-            inner: BlindedMessagesSdk::random(*amount.as_ref().deref())?,
+            inner: BlindedMessagesSdk::random(
+                *keyset_id.as_ref().deref(),
+                *amount.as_ref().deref(),
+            )?,
         })
     }
 
-    pub fn blank(fee_reserve: Arc<Amount>) -> Result<Self> {
+    pub fn blank(keyset_id: Arc<Id>, fee_reserve: Arc<Amount>) -> Result<Self> {
         Ok(Self {
-            inner: BlindedMessagesSdk::blank(*fee_reserve.as_ref().deref())?,
+            inner: BlindedMessagesSdk::blank(
+                *keyset_id.as_ref().deref(),
+                *fee_reserve.as_ref().deref(),
+            )?,
         })
     }
 

+ 3 - 1
bindings/cashu-js/src/nuts/nut00/blinded_message.rs

@@ -4,6 +4,7 @@ use cashu::nuts::nut00::BlindedMessage;
 use wasm_bindgen::prelude::*;
 
 use crate::nuts::nut01::JsPublicKey;
+use crate::nuts::nut02::JsId;
 use crate::types::amount::JsAmount;
 
 #[wasm_bindgen(js_name = BlindedMessage)]
@@ -28,9 +29,10 @@ impl From<BlindedMessage> for JsBlindedMessage {
 impl JsBlindedMessage {
     #[allow(clippy::new_without_default)]
     #[wasm_bindgen(constructor)]
-    pub fn new(amount: JsAmount, b: JsPublicKey) -> Self {
+    pub fn new(keyset_id: JsId, amount: JsAmount, b: JsPublicKey) -> Self {
         Self {
             inner: BlindedMessage {
+                keyset_id: *keyset_id.deref(),
                 amount: *amount.deref(),
                 b: b.deref().clone(),
             },

+ 7 - 4
bindings/cashu-js/src/nuts/nut00/blinded_messages.rs

@@ -4,6 +4,7 @@ use cashu::nuts::nut00::wallet::BlindedMessages;
 use wasm_bindgen::prelude::*;
 
 use crate::error::{into_err, Result};
+use crate::nuts::nut02::JsId;
 use crate::types::JsAmount;
 
 #[wasm_bindgen(js_name = BlindedMessages)]
@@ -21,16 +22,18 @@ impl Deref for JsBlindedMessages {
 #[wasm_bindgen(js_class = BlindedMessages)]
 impl JsBlindedMessages {
     #[wasm_bindgen(js_name = random)]
-    pub fn random(amount: JsAmount) -> Result<JsBlindedMessages> {
+    pub fn random(keyset_id: JsId, amount: JsAmount) -> Result<JsBlindedMessages> {
         Ok(JsBlindedMessages {
-            inner: BlindedMessages::random(*amount.deref()).map_err(into_err)?,
+            inner: BlindedMessages::random(*keyset_id.deref(), *amount.deref())
+                .map_err(into_err)?,
         })
     }
 
     #[wasm_bindgen(js_name = blank)]
-    pub fn blank(fee_reserve: JsAmount) -> Result<JsBlindedMessages> {
+    pub fn blank(keyset_id: JsId, fee_reserve: JsAmount) -> Result<JsBlindedMessages> {
         Ok(JsBlindedMessages {
-            inner: BlindedMessages::blank(*fee_reserve.deref()).map_err(into_err)?,
+            inner: BlindedMessages::blank(*keyset_id.deref(), *fee_reserve.deref())
+                .map_err(into_err)?,
         })
     }
 

+ 3 - 3
bindings/cashu-sdk-ffi/src/cashu_sdk.udl

@@ -53,7 +53,7 @@ interface SecretKey {
 };
 
 interface BlindedMessage {
-	constructor(Amount amount, PublicKey b);
+	constructor(Id keyset_id, Amount amount, PublicKey b);
 	Amount amount();
 	PublicKey b();	
 };
@@ -103,9 +103,9 @@ interface Token {
 
 interface BlindedMessages {
     [Throws=CashuError, Name=random]
-	constructor(Amount amount);
+	constructor(Id keyset_id, Amount amount);
     [Throws=CashuError, Name=blank]
-	constructor(Amount fee_reserve);
+	constructor(Id keyset_id, Amount amount);
 	sequence<BlindedMessage> blinded_messages();
 	sequence<Secret> secrets();
 	sequence<SecretKey> rs();

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

@@ -119,7 +119,15 @@ impl Mint {
     }
 
     fn blind_sign(&self, blinded_message: &BlindedMessage) -> Result<BlindedSignature, Error> {
-        let BlindedMessage { amount, b } = blinded_message;
+        let BlindedMessage {
+            amount,
+            b,
+            keyset_id,
+        } = blinded_message;
+
+        if self.active_keyset.id.ne(keyset_id) {
+            return Err(Error::InactiveKeyset);
+        }
 
         let Some(key_pair) = self.active_keyset.keys.0.get(amount) else {
             // No key for amount

+ 5 - 5
crates/cashu-sdk/src/wallet.rs

@@ -98,7 +98,7 @@ impl<C: Client> Wallet<C> {
 
     /// Mint Proofs
     pub async fn mint(&self, amount: Amount, hash: &str) -> Result<Proofs, Error> {
-        let blinded_messages = BlindedMessages::random(amount)?;
+        let blinded_messages = BlindedMessages::random((&self.mint_keys).into(), amount)?;
 
         let mint_res = self
             .client
@@ -181,17 +181,17 @@ impl<C: Client> Wallet<C> {
         // amount first blinded messages are created for the amount
 
         let blinded_messages = if let Some(amount) = amount {
-            let mut desired_messages = BlindedMessages::random(amount)?;
+            let mut desired_messages = BlindedMessages::random((&self.mint_keys).into(), amount)?;
 
             let change_amount = proofs.iter().map(|p| p.amount).sum::<Amount>() - amount;
 
-            let change_messages = BlindedMessages::random(change_amount)?;
+            let change_messages = BlindedMessages::random((&self.mint_keys).into(), change_amount)?;
             desired_messages.combine(change_messages);
             desired_messages
         } else {
             let value = proofs.iter().map(|p| p.amount).sum();
 
-            BlindedMessages::random(value)?
+            BlindedMessages::random((&self.mint_keys).into(), value)?
         };
 
         let split_payload = SplitRequest::new(proofs, blinded_messages.blinded_messages.clone());
@@ -308,7 +308,7 @@ impl<C: Client> Wallet<C> {
         proofs: Proofs,
         fee_reserve: Amount,
     ) -> Result<Melted, Error> {
-        let blinded = BlindedMessages::blank(fee_reserve)?;
+        let blinded = BlindedMessages::blank((&self.mint_keys).into(), fee_reserve)?;
         let melt_response = self
             .client
             .post_melt(

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

@@ -101,6 +101,9 @@ pub mod mint {
         /// Duplicate Proofs sent in request
         #[error("Duplicate proofs")]
         DuplicateProofs,
+        /// Keyset id not active
+        #[error("Keyset id is not active")]
+        InactiveKeyset,
         #[error("`{0}`")]
         CustomError(String),
     }

+ 15 - 6
crates/cashu/src/nuts/nut00.rs

@@ -16,6 +16,8 @@ pub struct BlindedMessage {
     /// encrypted secret message (B_)
     #[serde(rename = "B_")]
     pub b: PublicKey,
+    #[serde(rename = "id")]
+    pub keyset_id: Id,
 }
 
 #[cfg(feature = "wallet")]
@@ -30,7 +32,7 @@ pub mod wallet {
     use super::MintProofs;
     use crate::dhke::blind_message;
     use crate::error::wallet;
-    use crate::nuts::{BlindedMessage, Proofs, SecretKey};
+    use crate::nuts::{BlindedMessage, Id, Proofs, SecretKey};
     use crate::secret::Secret;
     use crate::url::UncheckedUrl;
     use crate::{error, Amount};
@@ -50,14 +52,18 @@ pub mod wallet {
 
     impl BlindedMessages {
         /// Outputs for speceifed amount with random secret
-        pub fn random(amount: Amount) -> Result<Self, wallet::Error> {
+        pub fn random(keyset_id: Id, amount: Amount) -> Result<Self, wallet::Error> {
             let mut blinded_messages = BlindedMessages::default();
 
             for amount in amount.split() {
                 let secret = Secret::new();
                 let (blinded, r) = blind_message(secret.as_bytes(), None)?;
 
-                let blinded_message = BlindedMessage { amount, b: blinded };
+                let blinded_message = BlindedMessage {
+                    amount,
+                    b: blinded,
+                    keyset_id,
+                };
 
                 blinded_messages.secrets.push(secret);
                 blinded_messages.blinded_messages.push(blinded_message);
@@ -69,7 +75,7 @@ pub mod wallet {
         }
 
         /// Blank Outputs used for NUT-08 change
-        pub fn blank(fee_reserve: Amount) -> Result<Self, wallet::Error> {
+        pub fn blank(keyset_id: Id, fee_reserve: Amount) -> Result<Self, wallet::Error> {
             let mut blinded_messages = BlindedMessages::default();
 
             let fee_reserve = bitcoin::Amount::from_sat(fee_reserve.to_sat());
@@ -87,6 +93,7 @@ pub mod wallet {
                 let blinded_message = BlindedMessage {
                     amount: Amount::ZERO,
                     b: blinded,
+                    keyset_id,
                 };
 
                 blinded_messages.secrets.push(secret);
@@ -322,10 +329,12 @@ mod tests {
 
     #[test]
     fn test_blank_blinded_messages() {
-        let b = BlindedMessages::blank(Amount::from_sat(1000)).unwrap();
+        // TODO: Need to update id to new type in proof
+        let b = BlindedMessages::blank(Id::from_str("").unwrap(), Amount::from_sat(1000)).unwrap();
         assert_eq!(b.blinded_messages.len(), 10);
 
-        let b = BlindedMessages::blank(Amount::from_sat(1)).unwrap();
+        // TODO: Need to update id to new type in proof
+        let b = BlindedMessages::blank(Id::from_str("").unwrap(), Amount::from_sat(1)).unwrap();
         assert_eq!(b.blinded_messages.len(), 1);
     }
 }

+ 1 - 1
crates/cashu/src/nuts/nut02.rs

@@ -51,7 +51,7 @@ impl std::fmt::Display for Id {
         f.write_str(&format!(
             "{}{}",
             self.version,
-            String::from_utf8(self.id.to_vec()).map_err(|_| fmt::Error::default())?
+            String::from_utf8(self.id.to_vec()).map_err(|_| fmt::Error)?
         ))
     }
 }