فهرست منبع

Make sure signatory has all the keys in memory

Drop also foreign constraints on sqlite
Cesar Rodas 1 هفته پیش
والد
کامیت
f93bd1799b

+ 7 - 3
crates/cdk-integration-tests/src/init_auth_mint.rs

@@ -4,23 +4,25 @@ use std::sync::Arc;
 use anyhow::Result;
 use bip39::Mnemonic;
 use cashu::{AuthRequired, Method, ProtectedEndpoint, RoutePath};
-use cdk::cdk_database::{self, MintAuthDatabase, MintDatabase};
+use cdk::cdk_database::{self, MintAuthDatabase, MintDatabase, MintKeysDatabase};
 use cdk::mint::{MintBuilder, MintMeltLimits};
 use cdk::nuts::{CurrencyUnit, PaymentMethod};
 use cdk::types::FeeReserve;
 use cdk::wallet::AuthWallet;
 use cdk_fake_wallet::FakeWallet;
 
-pub async fn start_fake_mint_with_auth<D, A>(
+pub async fn start_fake_mint_with_auth<D, A, K>(
     _addr: &str,
     _port: u16,
     openid_discovery: String,
     database: D,
     auth_database: A,
+    key_store: K,
 ) -> Result<()>
 where
     D: MintDatabase<cdk_database::Error> + Send + Sync + 'static,
     A: MintAuthDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
+    K: MintKeysDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
 {
     let fee_reserve = FeeReserve {
         min_fee_reserve: 1.into(),
@@ -31,7 +33,9 @@ where
 
     let mut mint_builder = MintBuilder::new();
 
-    mint_builder = mint_builder.with_localstore(Arc::new(database));
+    mint_builder = mint_builder
+        .with_localstore(Arc::new(database))
+        .with_keystore(Arc::new(key_store));
 
     mint_builder = mint_builder
         .add_ln_backend(

+ 39 - 31
crates/cdk-integration-tests/src/init_pure_tests.rs

@@ -9,7 +9,7 @@ use anyhow::{anyhow, bail, Result};
 use async_trait::async_trait;
 use bip39::Mnemonic;
 use cdk::amount::SplitTarget;
-use cdk::cdk_database::{self, MintDatabase, WalletDatabase};
+use cdk::cdk_database::{self, WalletDatabase};
 use cdk::mint::{MintBuilder, MintMeltLimits};
 use cdk::nuts::nut00::ProofsMethods;
 use cdk::nuts::{
@@ -179,40 +179,42 @@ pub fn setup_tracing() {
 }
 
 pub async fn create_and_start_test_mint() -> Result<Mint> {
-    let mut mint_builder = MintBuilder::new();
-
     // Read environment variable to determine database type
     let db_type = env::var("CDK_TEST_DB_TYPE").expect("Database type set");
 
-    let localstore: Arc<dyn MintDatabase<cdk_database::Error> + Send + Sync> =
-        match db_type.to_lowercase().as_str() {
-            "sqlite" => {
-                // Create a temporary directory for SQLite database
-                let temp_dir = create_temp_dir("cdk-test-sqlite-mint")?;
-                let path = temp_dir.join("mint.db").to_str().unwrap().to_string();
-                let database = cdk_sqlite::MintSqliteDatabase::new(&path)
+    let mut mint_builder = match db_type.to_lowercase().as_str() {
+        "sqlite" => {
+            // Create a temporary directory for SQLite database
+            let temp_dir = create_temp_dir("cdk-test-sqlite-mint")?;
+            let path = temp_dir.join("mint.db").to_str().unwrap().to_string();
+            let database = Arc::new(
+                cdk_sqlite::MintSqliteDatabase::new(&path)
                     .await
-                    .expect("Could not create sqlite db");
-                Arc::new(database)
-            }
-            "redb" => {
-                // Create a temporary directory for ReDB database
-                let temp_dir = create_temp_dir("cdk-test-redb-mint")?;
-                let path = temp_dir.join("mint.redb");
-                let database = cdk_redb::MintRedbDatabase::new(&path)
-                    .expect("Could not create redb mint database");
-                Arc::new(database)
-            }
-            "memory" => {
-                let database = cdk_sqlite::mint::memory::empty().await?;
-                Arc::new(database)
-            }
-            _ => {
-                bail!("Db type not set")
-            }
-        };
-
-    mint_builder = mint_builder.with_localstore(localstore.clone());
+                    .expect("Could not create sqlite db"),
+            );
+            MintBuilder::new()
+                .with_localstore(database.clone())
+                .with_keystore(database)
+        }
+        "redb" => {
+            // Create a temporary directory for ReDB database
+            let temp_dir = create_temp_dir("cdk-test-redb-mint")?;
+            let path = temp_dir.join("mint.redb");
+            let database = Arc::new(
+                cdk_redb::MintRedbDatabase::new(&path)
+                    .expect("Could not create redb mint database"),
+            );
+            MintBuilder::new()
+                .with_localstore(database.clone())
+                .with_keystore(database)
+        }
+        "memory" => MintBuilder::new()
+            .with_localstore(Arc::new(cdk_sqlite::mint::memory::empty().await?))
+            .with_keystore(Arc::new(cdk_sqlite::mint::memory::empty().await?)),
+        _ => {
+            bail!("Db type not set")
+        }
+    };
 
     let fee_reserve = FeeReserve {
         min_fee_reserve: 1.into(),
@@ -243,6 +245,12 @@ pub async fn create_and_start_test_mint() -> Result<Mint> {
         .with_urls(vec!["https://aaa".to_string()])
         .with_seed(mnemonic.to_seed_normalized("").to_vec());
 
+    let localstore = mint_builder
+        .localstore
+        .as_ref()
+        .map(|x| x.clone())
+        .expect("localstore");
+
     localstore
         .set_mint_info(mint_builder.mint_info.clone())
         .await?;

+ 3 - 1
crates/cdk-integration-tests/tests/mint.rs

@@ -32,7 +32,9 @@ async fn test_correct_keyset() -> Result<()> {
 
     let mut mint_builder = MintBuilder::new();
     let localstore = Arc::new(database);
-    mint_builder = mint_builder.with_localstore(localstore.clone());
+    mint_builder = mint_builder
+        .with_localstore(localstore.clone())
+        .with_keystore(localstore.clone());
 
     mint_builder = mint_builder
         .add_ln_backend(

+ 23 - 22
crates/cdk-mintd/src/main.rs

@@ -12,7 +12,7 @@ use std::sync::Arc;
 use anyhow::{anyhow, bail, Result};
 use axum::Router;
 use bip39::Mnemonic;
-use cdk::cdk_database::{self, MintAuthDatabase, MintDatabase};
+use cdk::cdk_database::{self, MintAuthDatabase};
 use cdk::mint::{MintBuilder, MintMeltLimits};
 // Feature-gated imports
 #[cfg(any(
@@ -108,8 +108,6 @@ async fn main() -> anyhow::Result<()> {
         None => work_dir.join("config.toml"),
     };
 
-    let mut mint_builder = MintBuilder::new();
-
     let mut settings = if config_file_arg.exists() {
         config::Settings::new(Some(config_file_arg))
     } else {
@@ -121,25 +119,28 @@ async fn main() -> anyhow::Result<()> {
     // ENV VARS will take **priority** over those in the config
     let settings = settings.from_env()?;
 
-    let localstore: Arc<dyn MintDatabase<cdk_database::Error> + Send + Sync> =
-        match settings.database.engine {
-            DatabaseEngine::Sqlite => {
-                let sql_db_path = work_dir.join("cdk-mintd.sqlite");
-                #[cfg(not(feature = "sqlcipher"))]
-                let sqlite_db = MintSqliteDatabase::new(&sql_db_path).await?;
-                #[cfg(feature = "sqlcipher")]
-                let sqlite_db = MintSqliteDatabase::new(&sql_db_path, args.password).await?;
-
-                Arc::new(sqlite_db)
-            }
-            #[cfg(feature = "redb")]
-            DatabaseEngine::Redb => {
-                let redb_path = work_dir.join("cdk-mintd.redb");
-                Arc::new(MintRedbDatabase::new(&redb_path)?)
-            }
-        };
-
-    mint_builder = mint_builder.with_localstore(localstore);
+    let mut mint_builder = match settings.database.engine {
+        DatabaseEngine::Sqlite => {
+            let sql_db_path = work_dir.join("cdk-mintd.sqlite");
+            #[cfg(not(feature = "sqlcipher"))]
+            let sqlite_db = MintSqliteDatabase::new(&sql_db_path).await?;
+            #[cfg(feature = "sqlcipher")]
+            let sqlite_db = MintSqliteDatabase::new(&sql_db_path, args.password).await?;
+
+            let db = Arc::new(sqlite_db);
+            MintBuilder::new()
+                .with_localstore(db.clone())
+                .with_keystore(db)
+        }
+        #[cfg(feature = "redb")]
+        DatabaseEngine::Redb => {
+            let redb_path = work_dir.join("cdk-mintd.redb");
+            let db = Arc::new(MintRedbDatabase::new(&redb_path)?);
+            MintBuilder::new()
+                .with_localstore(db.clone())
+                .with_keystore(db)
+        }
+    };
 
     let mut contact_info: Option<Vec<ContactInfo>> = None;
 

+ 71 - 142
crates/cdk-signatory/src/memory.rs → crates/cdk-signatory/src/db_signatory.rs

@@ -3,16 +3,11 @@ use std::sync::Arc;
 
 use bitcoin::bip32::{DerivationPath, Xpriv};
 use bitcoin::secp256k1::{self, Secp256k1};
-use cdk_common::amount::Amount;
 use cdk_common::database;
 use cdk_common::dhke::{sign_message, verify_message};
 use cdk_common::error::Error;
 use cdk_common::mint::MintKeySetInfo;
-use cdk_common::nuts::nut01::MintKeyPair;
-use cdk_common::nuts::{
-    self, BlindSignature, BlindedMessage, CurrencyUnit, Id, Kind, MintKeySet, Proof,
-};
-use cdk_common::secret;
+use cdk_common::nuts::{BlindSignature, BlindedMessage, CurrencyUnit, Id, MintKeySet, Proof};
 use tokio::sync::RwLock;
 
 use crate::common::{create_new_keyset, derivation_path_from_unit, init_keysets};
@@ -24,8 +19,9 @@ use crate::signatory::{RotateKeyArguments, Signatory, SignatoryKeySet};
 ///
 /// The private keys and the all key-related data is stored in memory, in the same process, but it
 /// is not accessible from the outside.
-pub struct Memory {
+pub struct DbSignatory {
     keysets: RwLock<HashMap<Id, (MintKeySetInfo, MintKeySet)>>,
+    active_keysets: RwLock<HashMap<CurrencyUnit, Id>>,
     localstore: Arc<dyn database::MintKeysDatabase<Err = database::Error> + Send + Sync>,
     auth_localstore:
         Option<Arc<dyn database::MintAuthDatabase<Err = database::Error> + Send + Sync>>,
@@ -34,7 +30,7 @@ pub struct Memory {
     xpriv: Xpriv,
 }
 
-impl Memory {
+impl DbSignatory {
     /// Creates a new MemorySignatory instance
     pub async fn new(
         localstore: Arc<dyn database::MintKeysDatabase<Err = database::Error> + Send + Sync>,
@@ -108,111 +104,71 @@ impl Memory {
             }
         }
 
-        Ok(Self {
-            keysets: RwLock::new(HashMap::new()),
+        let keys = Self {
+            keysets: Default::default(),
+            active_keysets: Default::default(),
             auth_localstore,
             secp_ctx,
             localstore,
             custom_paths,
             xpriv,
-        })
-    }
-}
+        };
+        keys.reload_keys_from_db().await?;
 
-impl Memory {
-    fn generate_keyset(&self, keyset_info: MintKeySetInfo) -> MintKeySet {
-        MintKeySet::generate_from_xpriv(
-            &self.secp_ctx,
-            self.xpriv,
-            keyset_info.max_order,
-            keyset_info.unit,
-            keyset_info.derivation_path,
-        )
+        Ok(keys)
     }
 
-    async fn load_and_get_keyset(&self, id: &Id) -> Result<MintKeySetInfo, Error> {
-        let keysets = self.keysets.read().await;
-        let keyset_info = if let Some(info) = self.localstore.get_keyset_info(id).await? {
-            info
-        } else {
-            let auth_localstore = self.auth_localstore.as_ref().ok_or(Error::UnknownKeySet)?;
-            let keyset_info = auth_localstore
-                .get_keyset_info(id)
-                .await?
-                .ok_or(Error::UnknownKeySet)?;
+    /// Load all the keysets from the database, even if they are not active.
+    ///
+    /// Since the database is owned by this process, we can load all the keysets in memory, and use
+    /// it as the primary source, and the database as the persistence layer.
+    ///
+    /// Any operation performed with keysets, are done through this trait and never to the database
+    /// directly.
+    async fn reload_keys_from_db(&self) -> Result<(), Error> {
+        let mut keysets = self.keysets.write().await;
+        let mut active_keysets = self.active_keysets.write().await;
+        keysets.clear();
+        active_keysets.clear();
+        for info in self.localstore.get_keyset_infos().await? {
+            let id = info.id;
+            let keyset = self.generate_keyset(&info);
+            if info.active {
+                active_keysets.insert(info.unit.clone(), id);
+            }
+            keysets.insert(id, (info, keyset));
+        }
 
-            let active = match auth_localstore.get_active_keyset_id().await {
-                Ok(Some(id)) => id,
-                Ok(None) => {
-                    tracing::error!("No active keyset found");
-                    return Err(Error::InactiveKeyset);
+        if let Some(auth_db) = self.auth_localstore.clone() {
+            for info in auth_db.get_keyset_infos().await? {
+                let id = info.id;
+                let keyset = self.generate_keyset(&info);
+                if info.unit != CurrencyUnit::Auth {
+                    continue;
                 }
-                Err(e) => {
-                    tracing::error!("Error retrieving active keyset ID: {:?}", e);
-                    return Err(e.into());
+                if info.active {
+                    active_keysets.insert(info.unit.clone(), id);
                 }
-            };
-
-            // Check that the keyset is active and should be used to sign
-            if keyset_info.id.ne(&active) {
-                tracing::warn!(
-                    "Keyset {:?} is not active. Active keyset is {:?}",
-                    keyset_info.id,
-                    active
-                );
-                return Err(Error::InactiveKeyset);
+                keysets.insert(id, (info, keyset));
             }
-
-            keyset_info
-        };
-
-        if keysets.contains_key(id) {
-            return Ok(keyset_info);
         }
-        drop(keysets);
 
-        let id = keyset_info.id;
-        let mut keysets = self.keysets.write().await;
-        keysets.insert(
-            id,
-            (
-                keyset_info.clone(),
-                self.generate_keyset(keyset_info.clone()),
-            ),
-        );
-        Ok(keyset_info)
+        Ok(())
     }
 
-    #[tracing::instrument(skip(self))]
-    async fn get_keypair_for_amount(
-        &self,
-        keyset_id: &Id,
-        amount: &Amount,
-    ) -> Result<MintKeyPair, Error> {
-        let keyset_info = self.load_and_get_keyset(keyset_id).await?;
-        let active = self
-            .localstore
-            .get_active_keyset_id(&keyset_info.unit)
-            .await?
-            .ok_or(Error::InactiveKeyset)?;
-
-        // Check that the keyset is active and should be used to sign
-        if keyset_info.id != active {
-            return Err(Error::InactiveKeyset);
-        }
-
-        let keysets = self.keysets.read().await;
-        let keyset = keysets.get(keyset_id).ok_or(Error::UnknownKeySet)?;
-
-        match keyset.1.keys.get(amount) {
-            Some(key_pair) => Ok(key_pair.clone()),
-            None => Err(Error::AmountKey),
-        }
+    fn generate_keyset(&self, keyset_info: &MintKeySetInfo) -> MintKeySet {
+        MintKeySet::generate_from_xpriv(
+            &self.secp_ctx,
+            self.xpriv,
+            keyset_info.max_order,
+            keyset_info.unit.clone(),
+            keyset_info.derivation_path.clone(),
+        )
     }
 }
 
 #[async_trait::async_trait]
-impl Signatory for Memory {
+impl Signatory for DbSignatory {
     async fn blind_sign(&self, blinded_message: BlindedMessage) -> Result<BlindSignature, Error> {
         let BlindedMessage {
             amount,
@@ -220,7 +176,14 @@ impl Signatory for Memory {
             keyset_id,
             ..
         } = blinded_message;
-        let key_pair = self.get_keypair_for_amount(&keyset_id, &amount).await?;
+
+        let keysets = self.keysets.read().await;
+        let (info, key) = keysets.get(&keyset_id).ok_or(Error::UnknownKeySet)?;
+        if !info.active {
+            return Err(Error::InactiveKeyset);
+        }
+
+        let key_pair = key.keys.get(&amount).ok_or(Error::UnknownKeySet)?;
         let c = sign_message(&key_pair.secret_key, &blinded_secret)?;
 
         let blinded_signature = BlindSignature::new(
@@ -228,56 +191,30 @@ impl Signatory for Memory {
             c,
             keyset_id,
             &blinded_message.blinded_secret,
-            key_pair.secret_key,
+            key_pair.secret_key.clone(),
         )?;
 
         Ok(blinded_signature)
     }
 
     async fn verify_proof(&self, proof: Proof) -> Result<(), Error> {
-        // Check if secret is a nut10 secret with conditions
-        if let Ok(secret) =
-            <&secret::Secret as TryInto<nuts::nut10::Secret>>::try_into(&proof.secret)
-        {
-            // Checks and verifies known secret kinds.
-            // If it is an unknown secret kind it will be treated as a normal secret.
-            // Spending conditions will **not** be check. It is up to the wallet to ensure
-            // only supported secret kinds are used as there is no way for the mint to
-            // enforce only signing supported secrets as they are blinded at
-            // that point.
-            match secret.kind {
-                Kind::P2PK => {
-                    proof.verify_p2pk()?;
-                }
-                Kind::HTLC => {
-                    proof.verify_htlc()?;
-                }
-            }
-        }
-
-        let key_pair = self
-            .get_keypair_for_amount(&proof.keyset_id, &proof.amount)
-            .await?;
-
+        let keysets = self.keysets.read().await;
+        let (_, key) = keysets.get(&proof.keyset_id).ok_or(Error::UnknownKeySet)?;
+        let key_pair = key.keys.get(&proof.amount).ok_or(Error::UnknownKeySet)?;
         verify_message(&key_pair.secret_key, proof.c, proof.secret.as_bytes())?;
 
         Ok(())
     }
 
     async fn auth_keysets(&self) -> Result<Option<Vec<SignatoryKeySet>>, Error> {
-        let db = if let Some(db) = self.auth_localstore.as_ref() {
-            db.clone()
-        } else {
-            return Ok(None);
-        };
-
-        let keyset_id: Id = db
-            .get_active_keyset_id()
-            .await?
+        let keyset_id = self
+            .active_keysets
+            .read()
+            .await
+            .get(&CurrencyUnit::Auth)
+            .cloned()
             .ok_or(Error::NoActiveKeyset)?;
 
-        _ = self.load_and_get_keyset(&keyset_id).await?;
-
         let active_keyset = self
             .keysets
             .read()
@@ -290,19 +227,12 @@ impl Signatory for Memory {
     }
 
     async fn keysets(&self) -> Result<Vec<SignatoryKeySet>, Error> {
-        for (_, id) in self.localstore.get_active_keysets().await? {
-            let _ = self.load_and_get_keyset(&id).await?;
-        }
-
         Ok(self
             .keysets
             .read()
             .await
             .values()
-            .filter_map(|k| match k.0.active {
-                true => Some(k.into()),
-                false => None,
-            })
+            .map(|k| k.into())
             .collect::<Vec<_>>())
     }
 
@@ -334,7 +264,7 @@ impl Signatory for Memory {
                 .ok_or(Error::UnsupportedUnit)?,
         };
 
-        let (keyset, keyset_info) = create_new_keyset(
+        let (_, keyset_info) = create_new_keyset(
             &self.secp_ctx,
             self.xpriv,
             derivation_path,
@@ -347,8 +277,7 @@ impl Signatory for Memory {
         self.localstore.add_keyset_info(keyset_info.clone()).await?;
         self.localstore.set_active_keyset(args.unit, id).await?;
 
-        let mut keysets = self.keysets.write().await;
-        keysets.insert(id, (keyset_info.clone(), keyset));
+        self.reload_keys_from_db().await?;
 
         Ok(keyset_info)
     }
@@ -360,8 +289,8 @@ mod test {
 
     use bitcoin::key::Secp256k1;
     use bitcoin::Network;
+    use cashu::{Amount, PublicKey};
     use cdk_common::MintKeySet;
-    use nuts::PublicKey;
 
     use super::*;
 

+ 1 - 1
crates/cdk-signatory/src/lib.rs

@@ -14,6 +14,6 @@ pub use proto::{client::SignatoryRpcClient, server::grpc_server};
 
 mod common;
 
-pub mod memory;
+pub mod db_signatory;
 pub mod service;
 pub mod signatory;

+ 31 - 0
crates/cdk-sqlite/src/mint/migrations/20250415093121_drop_keystore_foreign.sql

@@ -0,0 +1,31 @@
+CREATE TABLE proof_new (
+    y BLOB PRIMARY KEY,
+    amount INTEGER NOT NULL,
+    keyset_id TEXT NOT NULL, -- no FK constraint here
+    secret TEXT NOT NULL,
+    c BLOB NOT NULL,
+    witness TEXT,
+    state TEXT CHECK (state IN ('SPENT', 'PENDING', 'UNSPENT', 'RESERVED', 'UNKNOWN')) NOT NULL,
+    quote_id TEXT,
+    created_time INTEGER NOT NULL DEFAULT 0
+);
+
+INSERT INTO proof_new SELECT * FROM proof;
+DROP TABLE proof;
+ALTER TABLE proof_new RENAME TO proof;
+
+
+CREATE TABLE blind_signature_new (
+    y BLOB PRIMARY KEY,
+    amount INTEGER NOT NULL,
+    keyset_id TEXT NOT NULL,  -- FK removed
+    c BLOB NOT NULL,
+    dleq_e TEXT,
+    dleq_s TEXT,
+    quote_id TEXT,
+    created_time INTEGER NOT NULL DEFAULT 0
+);
+
+INSERT INTO blind_signature_new SELECT * FROM blind_signature;
+DROP TABLE blind_signature;
+ALTER TABLE blind_signature_new RENAME TO blind_signature;

+ 3 - 3
crates/cdk/src/mint/builder.rs

@@ -33,8 +33,8 @@ pub struct MintBuilder {
     /// Mint Info
     pub mint_info: MintInfo,
     /// Mint Storage backend
-    localstore: Option<Arc<dyn MintDatabase<database::Error> + Send + Sync>>,
-    ///
+    pub localstore: Option<Arc<dyn MintDatabase<database::Error> + Send + Sync>>,
+    /// Database for the Signatory
     keystore: Option<Arc<dyn MintKeysDatabase<Err = database::Error> + Send + Sync>>,
     /// Mint Storage backend
     #[cfg(feature = "auth")]
@@ -338,7 +338,7 @@ impl MintBuilder {
             signatory.clone()
         } else {
             let seed = self.seed.as_ref().ok_or(anyhow!("Mint seed not set"))?;
-            let in_memory_signatory = cdk_signatory::memory::Memory::new(
+            let in_memory_signatory = cdk_signatory::db_signatory::DbSignatory::new(
                 self.keystore.clone().ok_or(anyhow!("keystore not set"))?,
                 None,
                 seed,

+ 1 - 0
crates/cdk/src/mint/keysets/mod.rs

@@ -35,6 +35,7 @@ impl Mint {
                 .keysets()
                 .await?
                 .into_iter()
+                .filter(|keyset| keyset.info.active && keyset.info.unit != CurrencyUnit::Auth)
                 .map(|key| key.key)
                 .collect::<Vec<_>>(),
         })

+ 25 - 2
crates/cdk/src/mint/mod.rs

@@ -9,6 +9,10 @@ use cdk_common::common::{PaymentProcessorKey, QuoteTTL};
 #[cfg(feature = "auth")]
 use cdk_common::database::MintAuthDatabase;
 use cdk_common::database::{self, MintDatabase};
+use cdk_common::nuts::{
+    self, BlindSignature, BlindedMessage, CurrencyUnit, Id, Kind, MintKeySet, Proof,
+};
+use cdk_common::secret;
 use cdk_signatory::signatory::Signatory;
 use futures::StreamExt;
 #[cfg(feature = "auth")]
@@ -350,6 +354,25 @@ impl Mint {
     /// Verify [`Proof`] meets conditions and is signed
     #[instrument(skip_all)]
     pub async fn verify_proof(&self, proof: &Proof) -> Result<(), Error> {
+        // Check if secret is a nut10 secret with conditions
+        if let Ok(secret) =
+            <&secret::Secret as TryInto<nuts::nut10::Secret>>::try_into(&proof.secret)
+        {
+            // Checks and verifies known secret kinds.
+            // If it is an unknown secret kind it will be treated as a normal secret.
+            // Spending conditions will **not** be check. It is up to the wallet to ensure
+            // only supported secret kinds are used as there is no way for the mint to
+            // enforce only signing supported secrets as they are blinded at
+            // that point.
+            match secret.kind {
+                Kind::P2PK => {
+                    proof.verify_p2pk()?;
+                }
+                Kind::HTLC => {
+                    proof.verify_htlc()?;
+                }
+            }
+        }
         self.signatory.verify_proof(proof.to_owned()).await
     }
 
@@ -559,7 +582,7 @@ mod tests {
         );
 
         let signatory = Arc::new(
-            cdk_signatory::memory::Memory::new(
+            cdk_signatory::db_signatory::DbSignatory::new(
                 localstore.clone(),
                 None,
                 config.seed,
@@ -630,7 +653,7 @@ mod tests {
 
         let keysets = mint.keysets().await.unwrap();
 
-        assert!(keysets.keysets.len().eq(&2));
+        assert_eq!(2, keysets.keysets.len());
         for keyset in &keysets.keysets {
             if keyset.id == first_keyset_id {
                 assert!(!keyset.active);