diff --git a/Cargo.toml b/Cargo.toml
index 680293395..4d99bd1d4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -64,3 +64,7 @@ required-features = ["std", "base64"]
 [workspace]
 members = ["bitcoind-tests", "fuzz"]
 exclude = ["embedded"]
+
+[[example]]
+name = "plan_spend"
+required-features = ["std", "base64"]
diff --git a/examples/plan_spend.rs b/examples/plan_spend.rs
new file mode 100644
index 000000000..77f5f6921
--- /dev/null
+++ b/examples/plan_spend.rs
@@ -0,0 +1,241 @@
+use std::collections::BTreeMap;
+use std::str::FromStr;
+
+use bitcoin::absolute::Height;
+use bitcoin::blockdata::locktime::absolute;
+use bitcoin::key::TapTweak;
+use bitcoin::psbt::{self, Psbt};
+use bitcoin::sighash::SighashCache;
+use bitcoin::{taproot, PrivateKey, ScriptBuf};
+use miniscript::bitcoin::consensus::encode::deserialize;
+use miniscript::bitcoin::hashes::hex::FromHex;
+use miniscript::bitcoin::{
+    self, base64, secp256k1, Address, Network, OutPoint, Sequence, Transaction, TxIn, TxOut,
+};
+use miniscript::psbt::{PsbtExt, PsbtInputExt};
+use miniscript::{Descriptor, DescriptorPublicKey};
+use secp256k1::Secp256k1;
+
+fn main() {
+    // Defining the descriptor keys required.
+    let secp256k1 = secp256k1::Secp256k1::new();
+    let keys = vec![
+        "036a7ae441409bd40af1b8efba7dbd34b822b9a72566eff10b889b8de13659e343",
+        "03b6c8a1a901edf3c5f1cb0e3ffe1f20393435a5d467f435e2858c9ab43d3ca78c",
+        "03500a2b48b0f66c8183cc0d6645ab21cc19c7fad8a33ff04d41c3ece54b0bc1c5",
+        "033ad2d191da4f39512adbaac320cae1f12f298386a4e9d43fd98dec7cf5db2ac9",
+        "023fc33527afab09fa97135f2180bcd22ce637b1d2fbcb2db748b1f2c33f45b2b4",
+    ];
+
+    // The taproot descriptor combines different spending paths and conditions, allowing the funds to be spent using
+    // different methods depending on the desired conditions.
+
+    // tr({A},{{pkh({B}),{{multi_a(1,{C},{D}),and_v(v:pk({E}),after(10))}}}}) represents a taproot spending policy.
+    // Let's break it down:
+    //
+    // * Key Spend Path
+    // {A} represents the public key for the taproot key spending path.
+    //
+    // * Script Spend Paths
+    // {B} represents the public key for the pay-to-pubkey-hash (P2PKH) spending path.
+    // The multi_a(1,{C},{D}) construct represents a 1-of-2 multi-signature script condition.
+    // It requires at least one signature from {C} and {D} to spend funds using the script spend path.
+    // The and_v(v:pk({E}),after(10)) construct represents a combination of a P2PK script condition and a time lock.
+    // It requires a valid signature from {E} and enforces a time lock of 10 blocks on spending funds.
+
+    // By constructing transactions using this taproot descriptor and signing them appropriately,
+    // you can create flexible spending policies that enable different spending paths and conditions depending on the
+    // transaction's inputs and outputs.
+    let s = format!(
+        "tr({},{{pkh({}),{{multi_a(1,{},{}),and_v(v:pk({}),after(10))}}}})",
+        keys[0], // Key A
+        keys[1], // Key B
+        keys[2], // Key C
+        keys[3], // Key D
+        keys[4], // Key E
+    );
+
+    let descriptor = Descriptor::from_str(&s).expect("parse descriptor string");
+    assert!(descriptor.sanity_check().is_ok());
+
+    println!("Descriptor pubkey script: {}", descriptor.script_pubkey());
+    println!("Descriptor address: {}", descriptor.address(Network::Regtest).unwrap());
+
+    let master_private_key_str = "KxQqtbUnMugSEbKHG3saknvVYux1cgFjFqWzMfwnFhLm8QrGq26v";
+    let master_private_key =
+        PrivateKey::from_str(master_private_key_str).expect("Can't create private key");
+    println!("Master public key: {}", master_private_key.public_key(&secp256k1));
+
+    let backup1_private_key_str = "Kwb9oFfPNt6D3Fa9DCF5emRvLyJ3UUvCHnVxp4xf7bWDxWmeVdeH";
+    let backup1_private =
+        PrivateKey::from_str(backup1_private_key_str).expect("Can't create private key");
+
+    println!("Backup1 public key: {}", backup1_private.public_key(&secp256k1));
+
+    let backup2_private_key_str = "cPJFWUKk8sdL7pcDKrmNiWUyqgovimmhaaZ8WwsByDaJ45qLREkh";
+    let backup2_private =
+        PrivateKey::from_str(backup2_private_key_str).expect("Can't create private key");
+
+    println!("Backup2 public key: {}", backup2_private.public_key(&secp256k1));
+
+    let backup3_private_key_str = "cT5cH9UVm81W5QAf5KABXb23RKNSMbMzMx85y6R2mF42L94YwKX6";
+    let _backup3_private =
+        PrivateKey::from_str(backup3_private_key_str).expect("Can't create private key");
+
+    println!("Backup3 public key: {}", _backup3_private.public_key(&secp256k1));
+
+    // Create a spending transaction
+    let spend_tx = Transaction {
+        version: 2,
+        lock_time: absolute::LockTime::Blocks(Height::ZERO),
+        input: vec![],
+        output: vec![],
+    };
+
+    let hex_tx = "020000000001018ff27041f3d738f5f84fd5ee62f1c5b36afebfb15f6da0c9d1382ddd0eaaa23c0000000000feffffff02b3884703010000001600142ca3b4e53f17991582d47b15a053b3201891df5200e1f5050000000022512061763f4288d086c0347c4e3c387ce22ab9372cecada6c326e77efd57e9a5ea460247304402207b820860a9d425833f729775880b0ed59dd12b64b9a3d1ab677e27e4d6b370700220576003163f8420fe0b9dc8df726cff22cbc191104a2d4ae4f9dfedb087fcec72012103817e1da42a7701df4db94db8576f0e3605f3ab3701608b7e56f92321e4d8999100000000";
+    let depo_tx: Transaction = deserialize(&Vec::<u8>::from_hex(hex_tx).unwrap()).unwrap();
+
+    let receiver = Address::from_str("bcrt1qsdks5za4t6sevaph6tz9ddfjzvhkdkxe9tfrcy").unwrap();
+
+    let amount = 100000000;
+
+    let (outpoint, witness_utxo) = get_vout(&depo_tx, descriptor.script_pubkey());
+
+    let all_assets = Descriptor::<DescriptorPublicKey>::from_str(&s)
+        .unwrap()
+        .all_assets()
+        .unwrap();
+
+    for asset in all_assets {
+        // Creating a PSBT Object
+        let mut psbt = Psbt {
+            unsigned_tx: spend_tx.clone(),
+            unknown: BTreeMap::new(),
+            proprietary: BTreeMap::new(),
+            xpub: BTreeMap::new(),
+            version: 0,
+            inputs: vec![],
+            outputs: vec![],
+        };
+
+        // Defining the Transaction Input
+        let mut txin = TxIn::default();
+        txin.previous_output = outpoint;
+        txin.sequence = Sequence::from_height(26); //Sequence::MAX; //
+        psbt.unsigned_tx.input.push(txin);
+
+        // Defining the Transaction Output
+        psbt.unsigned_tx.output.push(TxOut {
+            script_pubkey: receiver.payload.script_pubkey(),
+            value: amount / 5 - 500,
+        });
+
+        psbt.unsigned_tx
+            .output
+            .push(TxOut { script_pubkey: descriptor.script_pubkey(), value: amount * 4 / 5 });
+
+        // Consider that out of all the keys required to sign the descriptor spend path we only have some handful of assets.
+        // We can plan the PSBT with only few assets(keys or hashes) if that are enough for satisfying any policy.
+        //
+        // Here for example assume that we only have two keys available.
+        // Key A and Key B (as seen from the descriptor above)
+        // We have to add the keys to `Asset` and then obtain plan with only available signatures if  the descriptor can be satisfied.
+
+        // Obtain the Plan based on available Assets
+        let plan = descriptor.clone().plan(&asset).unwrap();
+
+        // Creating PSBT Input
+        let mut input = psbt::Input::default();
+        plan.update_psbt_input(&mut input);
+
+        // Update the PSBT input from the result which we have obtained from the Plan.
+        input.update_with_descriptor_unchecked(&descriptor).unwrap();
+        input.witness_utxo = Some(witness_utxo.clone());
+
+        // Push the PSBT Input and declare an PSBT Output Structure
+        psbt.inputs.push(input);
+        psbt.outputs.push(psbt::Output::default());
+
+        // Use private keys to sign
+        let key_a = master_private_key.inner;
+        let key_b = backup1_private.inner;
+
+        // Taproot script can be signed when we have either Key spend or Script spend or both.
+        // Here you can try to verify by commenting one of the spend path or try signing with both.
+        sign_taproot_psbt(&key_a, &mut psbt, &secp256k1); // Key Spend - With Key A
+        sign_taproot_psbt(&key_b, &mut psbt, &secp256k1); // Script Spend - With Key B
+
+        // Serializing and finalizing the PSBT Transaction
+        let serialized = psbt.serialize();
+        println!("{}", base64::encode(&serialized));
+        psbt.finalize_mut(&secp256k1).unwrap();
+
+        let tx = psbt.extract_tx();
+        println!("{}", bitcoin::consensus::encode::serialize_hex(&tx));
+    }
+}
+
+// Siging the Taproot PSBT Transaction
+fn sign_taproot_psbt(
+    secret_key: &secp256k1::SecretKey,
+    psbt: &mut psbt::Psbt,
+    secp256k1: &Secp256k1<secp256k1::All>,
+) {
+    // Creating signing entitites required
+    let hash_ty = bitcoin::sighash::TapSighashType::Default;
+    let mut sighash_cache = SighashCache::new(&psbt.unsigned_tx);
+
+    // Defining Keypair for given private key
+    let keypair = secp256k1::KeyPair::from_seckey_slice(&secp256k1, secret_key.as_ref()).unwrap();
+
+    // Checking if leaf hash exist or not.
+    // For Key Spend -> Leaf Hash is None
+    // For Script Spend -> Leaf Hash is Some(_)
+    // Convert this leaf_hash tree to a full map.
+    let (leaf_hashes, (_, _)) = &psbt.inputs[0].tap_key_origins[&keypair.x_only_public_key().0];
+    let leaf_hash = if !leaf_hashes.is_empty() {
+        Some(leaf_hashes[0])
+    } else {
+        None
+    };
+
+    let keypair = match leaf_hash {
+        None => keypair
+            .tap_tweak(&secp256k1, psbt.inputs[0].tap_merkle_root)
+            .to_inner(), // tweak for key spend
+        Some(_) => keypair, // no tweak for script spend
+    };
+
+    // Construct the message to input for schnorr signature
+    let msg = psbt
+        .sighash_msg(0, &mut sighash_cache, leaf_hash)
+        .unwrap()
+        .to_secp_msg();
+    let sig = secp256k1.sign_schnorr(&msg, &keypair);
+    let (pk, _parity) = keypair.x_only_public_key();
+    assert!(secp256k1.verify_schnorr(&sig, &msg, &pk).is_ok());
+
+    // Create final signature with corresponding hash type
+    let final_signature1 = taproot::Signature { hash_ty, sig };
+
+    if let Some(lh) = leaf_hash {
+        // Script Spend
+        psbt.inputs[0]
+            .tap_script_sigs
+            .insert((pk, lh), final_signature1);
+    } else {
+        // Key Spend
+        psbt.inputs[0].tap_key_sig = Some(final_signature1);
+        println!("{:#?}", psbt);
+    }
+}
+
+// Find the Outpoint by spk
+fn get_vout(tx: &Transaction, spk: ScriptBuf) -> (OutPoint, TxOut) {
+    for (i, txout) in tx.clone().output.into_iter().enumerate() {
+        if spk == txout.script_pubkey {
+            return (OutPoint::new(tx.txid(), i as u32), txout);
+        }
+    }
+    panic!("Only call get vout on functions which have the expected outpoint");
+}
diff --git a/examples/psbt_sign_finalize.rs b/examples/psbt_sign_finalize.rs
index 08abd5abe..b90016802 100644
--- a/examples/psbt_sign_finalize.rs
+++ b/examples/psbt_sign_finalize.rs
@@ -1,31 +1,53 @@
-// SPDX-License-Identifier: CC0-1.0
-
 use std::collections::BTreeMap;
 use std::str::FromStr;
 
+use bitcoin::sighash::SighashCache;
+use bitcoin::PrivateKey;
 use miniscript::bitcoin::consensus::encode::deserialize;
 use miniscript::bitcoin::hashes::hex::FromHex;
-use miniscript::bitcoin::psbt::{self, Psbt};
-use miniscript::bitcoin::sighash::SighashCache;
+use miniscript::bitcoin::psbt::PartiallySignedTransaction as Psbt;
 use miniscript::bitcoin::{
-    self, base64, secp256k1, Address, Network, OutPoint, PrivateKey, Script, Sequence, Transaction,
-    TxIn, TxOut,
+    self, base64, psbt, secp256k1, Address, Network, OutPoint, Script, Sequence, Transaction, TxIn,
+    TxOut,
 };
 use miniscript::psbt::{PsbtExt, PsbtInputExt};
-use miniscript::Descriptor;
+use miniscript::{Descriptor, DescriptorPublicKey};
 
 fn main() {
+    // Defining the descriptor keys
     let secp256k1 = secp256k1::Secp256k1::new();
+    let keys = vec![
+        "027a3565454fe1b749bccaef22aff72843a9c3efefd7b16ac54537a0c23f0ec0de",
+        "032d672a1a91cc39d154d366cd231983661b0785c7f27bc338447565844f4a6813",
+        "03417129311ed34c242c012cd0a3e0b9bca0065f742d0dfb63c78083ea6a02d4d9",
+        "025a687659658baeabdfc415164528065be7bcaade19342241941e556557f01e28",
+    ];
+    // The wsh descriptor indicates a Witness Script Hash, meaning the descriptor is for a SegWit script.
+    // wsh(or(pk(A),thresh(1,pkh(B),pkh(C),pkh(D))))
+
+    // Let's break it down:
+    // t:or_c specifies an "or" construct, which means the script can be satisfied by one of the given conditions:
+    // pk(A) OR thresh(1,pkh(B),pkh(C),pkh(D))
+    // Inside threshold condition atleast 1 out of all given conditions should satisfy.
+
+    // By constructing transactions using this wsh descriptor and signing them appropriately,
+    // you can create flexible spending policies that enable different spending paths and conditions depending on the
+    // transaction's inputs and outputs.
+    let s = format!(
+        "wsh(t:or_c(pk({}),v:thresh(1,pkh({}),a:pkh({}),a:pkh({}))))",
+        keys[0], // key A
+        keys[1], // key B
+        keys[2], // key C
+        keys[3], // key D
+    );
+    let descriptor = Descriptor::from_str(&s).expect("parse descriptor string");
 
-    let s = "wsh(t:or_c(pk(027a3565454fe1b749bccaef22aff72843a9c3efefd7b16ac54537a0c23f0ec0de),v:thresh(1,pkh(032d672a1a91cc39d154d366cd231983661b0785c7f27bc338447565844f4a6813),a:pkh(03417129311ed34c242c012cd0a3e0b9bca0065f742d0dfb63c78083ea6a02d4d9),a:pkh(025a687659658baeabdfc415164528065be7bcaade19342241941e556557f01e28))))#7hut9ukn";
-    let bridge_descriptor = Descriptor::from_str(&s).unwrap();
-    //let bridge_descriptor = Descriptor::<bitcoin::PublicKey>::from_str(&s).expect("parse descriptor string");
-    assert!(bridge_descriptor.sanity_check().is_ok());
-    println!("Bridge pubkey script: {}", bridge_descriptor.script_pubkey());
-    println!("Bridge address: {}", bridge_descriptor.address(Network::Regtest).unwrap());
+    assert!(descriptor.sanity_check().is_ok());
+    println!("descriptor pubkey script: {}", descriptor.script_pubkey());
+    println!("descriptor address: {}", descriptor.address(Network::Regtest).unwrap());
     println!(
         "Weight for witness satisfaction cost {}",
-        bridge_descriptor.max_weight_to_satisfy().unwrap()
+        descriptor.max_weight_to_satisfy().unwrap()
     );
 
     let master_private_key_str = "cQhdvB3McbBJdx78VSSumqoHQiSXs75qwLptqwxSQBNBMDxafvaw";
@@ -51,6 +73,7 @@ fn main() {
 
     println!("Backup3 public key: {}", _backup3_private.public_key(&secp256k1));
 
+    // Create a spending transaction
     let spend_tx = Transaction {
         version: 2,
         lock_time: bitcoin::absolute::LockTime::from_consensus(5000),
@@ -58,17 +81,6 @@ fn main() {
         output: vec![],
     };
 
-    // Spend one input and spend one output for simplicity.
-    let mut psbt = Psbt {
-        unsigned_tx: spend_tx,
-        unknown: BTreeMap::new(),
-        proprietary: BTreeMap::new(),
-        xpub: BTreeMap::new(),
-        version: 0,
-        inputs: vec![],
-        outputs: vec![],
-    };
-
     let hex_tx = "020000000001018ff27041f3d738f5f84fd5ee62f1c5b36afebfb15f6da0c9d1382ddd0eaaa23c0000000000feffffff02b3884703010000001600142ca3b4e53f17991582d47b15a053b3201891df5200e1f50500000000220020c0ebf552acd2a6f5dee4e067daaef17b3521e283aeaa44a475278617e3d2238a0247304402207b820860a9d425833f729775880b0ed59dd12b64b9a3d1ab677e27e4d6b370700220576003163f8420fe0b9dc8df726cff22cbc191104a2d4ae4f9dfedb087fcec72012103817e1da42a7701df4db94db8576f0e3605f3ab3701608b7e56f92321e4d8999100000000";
     let depo_tx: Transaction = deserialize(&Vec::<u8>::from_hex(hex_tx).unwrap()).unwrap();
 
@@ -78,70 +90,97 @@ fn main() {
 
     let amount = 100000000;
 
-    let (outpoint, witness_utxo) = get_vout(&depo_tx, &bridge_descriptor.script_pubkey());
-
-    let mut txin = TxIn::default();
-    txin.previous_output = outpoint;
-
-    txin.sequence = Sequence::from_height(26); //Sequence::MAX; //
-    psbt.unsigned_tx.input.push(txin);
-
-    psbt.unsigned_tx
-        .output
-        .push(TxOut { script_pubkey: receiver.script_pubkey(), value: amount / 5 - 500 });
-
-    psbt.unsigned_tx
-        .output
-        .push(TxOut { script_pubkey: bridge_descriptor.script_pubkey(), value: amount * 4 / 5 });
-
-    // Generating signatures & witness data
-
-    let mut input = psbt::Input::default();
-    input
-        .update_with_descriptor_unchecked(&bridge_descriptor)
-        .unwrap();
-
-    input.witness_utxo = Some(witness_utxo.clone());
-    psbt.inputs.push(input);
-    psbt.outputs.push(psbt::Output::default());
+    let (outpoint, witness_utxo) = get_vout(&depo_tx, &descriptor.script_pubkey());
 
-    let mut sighash_cache = SighashCache::new(&psbt.unsigned_tx);
-
-    let msg = psbt
-        .sighash_msg(0, &mut sighash_cache, None)
+    let all_assets = Descriptor::<DescriptorPublicKey>::from_str(&s)
         .unwrap()
-        .to_secp_msg();
-
-    // Fixme: Take a parameter
-    let hash_ty = bitcoin::sighash::EcdsaSighashType::All;
-
-    let sk1 = backup1_private.inner;
-    let sk2 = backup2_private.inner;
-
-    // Finally construct the signature and add to psbt
-    let sig1 = secp256k1.sign_ecdsa(&msg, &sk1);
-    let pk1 = backup1_private.public_key(&secp256k1);
-    assert!(secp256k1.verify_ecdsa(&msg, &sig1, &pk1.inner).is_ok());
-
-    // Second key just in case
-    let sig2 = secp256k1.sign_ecdsa(&msg, &sk2);
-    let pk2 = backup2_private.public_key(&secp256k1);
-    assert!(secp256k1.verify_ecdsa(&msg, &sig2, &pk2.inner).is_ok());
-
-    psbt.inputs[0]
-        .partial_sigs
-        .insert(pk1, bitcoin::ecdsa::Signature { sig: sig1, hash_ty: hash_ty });
-
-    println!("{:#?}", psbt);
-
-    let serialized = psbt.serialize();
-    println!("{}", base64::encode(&serialized));
-
-    psbt.finalize_mut(&secp256k1).unwrap();
-    println!("{:#?}", psbt);
+        .all_assets()
+        .unwrap();
 
-    let tx = psbt.extract_tx();
-    println!("{}", bitcoin::consensus::encode::serialize_hex(&tx));
+    for asset in all_assets {
+        // Spend one input and spend one output for simplicity.
+        let mut psbt = Psbt {
+            unsigned_tx: spend_tx.clone(),
+            unknown: BTreeMap::new(),
+            proprietary: BTreeMap::new(),
+            xpub: BTreeMap::new(),
+            version: 0,
+            inputs: vec![],
+            outputs: vec![],
+        };
+
+        // Defining the Transaction Input
+        let mut txin = TxIn::default();
+        txin.previous_output = outpoint;
+        txin.sequence = Sequence::from_height(26); //Sequence::MAX; //
+        psbt.unsigned_tx.input.push(txin);
+
+        // Defining the Transaction Output
+        psbt.unsigned_tx
+            .output
+            .push(TxOut { script_pubkey: receiver.script_pubkey(), value: amount / 5 - 500 });
+
+        psbt.unsigned_tx
+            .output
+            .push(TxOut { script_pubkey: descriptor.script_pubkey(), value: amount * 4 / 5 });
+
+        // Consider that out of all the keys required to sign the descriptor, we only have some handful of assets.
+        // We can plan the PSBT with only few assets(keys or hashes) if that are enough for satisfying any policy.
+        //
+        // Here for example assume that we only have one key available i.e Key A(as seen from the descriptor above)
+        // Key A is enough to satisfy the given descriptor because it is OR.
+        // We have to add the key to `Asset` and then obtain plan with only available signature if  the descriptor can be satisfied.
+
+        // Check the possible asset which we can use
+        println!("{:#?}", asset);
+
+        // Obtain the Plan based on available Assets
+        let plan = descriptor.clone().plan(&asset).unwrap();
+
+        // Creating a PSBT Input
+        let mut input = psbt::Input::default();
+
+        // Update the PSBT input from the result which we have obtained from the Plan.
+        plan.update_psbt_input(&mut input);
+        input.update_with_descriptor_unchecked(&descriptor).unwrap();
+        input.witness_utxo = Some(witness_utxo.clone());
+
+        // Push the PSBT Input and declare an PSBT Output Structure
+        psbt.inputs.push(input);
+        psbt.outputs.push(psbt::Output::default());
+
+        let mut sighash_cache = SighashCache::new(&psbt.unsigned_tx);
+
+        let msg = psbt
+            .sighash_msg(0, &mut sighash_cache, None)
+            .unwrap()
+            .to_secp_msg();
+
+        // Fixme: Take a parameter
+        let hash_ty = bitcoin::sighash::EcdsaSighashType::All;
+
+        let sk = backup1_private.inner;
+
+        // Finally construct the signature and add to psbt
+        let sig = secp256k1.sign_ecdsa(&msg, &sk);
+        let key_a = backup1_private.public_key(&secp256k1);
+        assert!(secp256k1.verify_ecdsa(&msg, &sig, &key_a.inner).is_ok());
+
+        psbt.inputs[0]
+            .partial_sigs
+            .insert(key_a, bitcoin::ecdsa::Signature { sig, hash_ty });
+
+        println!("{:#?}", psbt);
+
+        let serialized = psbt.serialize();
+        println!("{}", base64::encode(&serialized));
+
+        psbt.finalize_mut(&secp256k1).unwrap();
+        println!("{:#?}", psbt);
+
+        let tx = psbt.extract_tx();
+        println!("{}", bitcoin::consensus::encode::serialize_hex(&tx));
+    }
 }
 
 // Find the Outpoint by spk
diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs
index 616bb37cc..e9c48e1c5 100644
--- a/src/descriptor/mod.rs
+++ b/src/descriptor/mod.rs
@@ -23,8 +23,9 @@ use sync::Arc;
 use self::checksum::verify_checksum;
 use crate::miniscript::decode::Terminal;
 use crate::miniscript::{satisfy, Legacy, Miniscript, Segwitv0};
-use crate::plan::{AssetProvider, Plan};
+use crate::plan::{AssetProvider, Assets, Plan};
 use crate::prelude::*;
+use crate::util::{asset_combination, k_of_n};
 use crate::{
     expression, hash256, BareCtx, Error, ForEachKey, MiniscriptKey, Satisfier, ToPublicKey,
     TranslateErr, TranslatePk, Translator,
@@ -546,6 +547,118 @@ impl Descriptor<DefiniteDescriptorKey> {
     }
 }
 
+impl Descriptor<DescriptorPublicKey> {
+    /// Count total possible assets for a given descriptor.
+    pub fn count_assets(&self) -> u32 {
+        match self {
+            Descriptor::Bare(k) => k.as_inner().count_assets(),
+            Descriptor::Pkh(_) => 1,
+            Descriptor::Wpkh(_) => 1,
+            Descriptor::Sh(k) => match k.as_inner() {
+                ShInner::Wsh(k) => match k.as_inner() {
+                    WshInner::SortedMulti(k) => {
+                        let n = k.pks.len() as u32;
+                        let k = k.k as u32;
+                        k_of_n(k, n).unwrap()
+                    }
+                    WshInner::Ms(k) => k.count_assets(),
+                },
+                ShInner::Wpkh(_) => 1,
+                ShInner::SortedMulti(k) => {
+                    let n = k.clone().pks.len() as u32;
+                    let k = k.clone().k as u32;
+                    k_of_n(k, n).unwrap()
+                }
+                ShInner::Ms(k) => k.count_assets(),
+            },
+            Descriptor::Wsh(k) => match k.as_inner() {
+                WshInner::SortedMulti(k) => {
+                    let n = k.clone().pks.len() as u32;
+                    let k = k.clone().k as u32;
+                    k_of_n(k, n).unwrap()
+                }
+                WshInner::Ms(k) => k.count_assets(),
+            },
+            Descriptor::Tr(k) => {
+                let s = k.tap_tree().clone().unwrap();
+                match s {
+                    TapTree::Tree { left, right, height: _ } => {
+                        let a = left.count_assets();
+                        let b = right.count_assets();
+                        a + b
+                    }
+                    TapTree::Leaf(k) => k.count_assets(),
+                }
+            }
+        }
+    }
+
+    /// Get all possible assets for a given descriptor
+    pub fn all_assets(&self) -> Result<Vec<Assets>, Error> {
+        let threshold = self.count_assets();
+        if threshold >= 1000 {
+            return Err(Error::MaxAssetThresholdExceeded);
+        }
+        match self {
+            Descriptor::Bare(k) => Ok(k.as_inner().all_assets()),
+            Descriptor::Pkh(k) => {
+                let mut asset = Assets::new();
+                asset = asset.add(k.as_inner().clone());
+                Ok(vec![asset])
+            }
+            Descriptor::Wpkh(k) => {
+                let mut asset = Assets::new();
+                asset = asset.add(k.as_inner().clone());
+                Ok(vec![asset])
+            }
+            Descriptor::Sh(k) => match k.as_inner() {
+                ShInner::Wsh(k) => match k.as_inner() {
+                    WshInner::SortedMulti(k) => {
+                        let dpk_v = k.clone().pks;
+                        let k = k.clone().k;
+                        Ok(asset_combination(k, &dpk_v))
+                    }
+                    WshInner::Ms(k) => Ok(k.all_assets()),
+                },
+                ShInner::Wpkh(k) => {
+                    let mut asset = Assets::new();
+                    asset = asset.add(k.as_inner().clone());
+                    Ok(vec![asset])
+                }
+                ShInner::SortedMulti(k) => {
+                    let dpk_v = k.clone().pks;
+                    let k = k.clone().k;
+                    Ok(asset_combination(k, &dpk_v))
+                }
+                ShInner::Ms(k) => Ok(k.all_assets()),
+            },
+            Descriptor::Wsh(k) => match k.as_inner() {
+                WshInner::SortedMulti(k) => {
+                    let dpk_v = k.clone().pks;
+                    let k = k.clone().k;
+                    Ok(asset_combination(k, &dpk_v))
+                }
+                WshInner::Ms(k) => {
+                    let a = k.all_assets();
+                    Ok(a)
+                }
+            },
+            Descriptor::Tr(k) => {
+                let s = k.tap_tree().clone().unwrap();
+                match s {
+                    TapTree::Tree { left, right, height: _ } => {
+                        let mut a = left.all_assets();
+                        let b = right.all_assets();
+                        a.extend(b);
+                        Ok(a)
+                    }
+                    TapTree::Leaf(k) => Ok(k.all_assets()),
+                }
+            }
+        }
+    }
+}
+
 impl<P, Q> TranslatePk<P, Q> for Descriptor<P>
 where
     P: MiniscriptKey,
@@ -2041,4 +2154,75 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
         Desc::from_str(&format!("tr({},pk({}))", x_only_key, uncomp_key)).unwrap_err();
         Desc::from_str(&format!("tr({},pk({}))", x_only_key, x_only_key)).unwrap();
     }
+
+    #[test]
+    fn test_all_assets_bare() {
+        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
+            "pk(0237b1c59ab055a8d3de40eaeb215c7b1922664b5ac049d849fb3346f81431e77f)",
+        )
+        .unwrap();
+
+        // Getting the assets from the all_assets method
+        let assets = descriptor.all_assets().unwrap();
+
+        let mut expected_asset = Assets::new();
+        expected_asset = expected_asset.add(
+            DescriptorPublicKey::from_str(
+                "0237b1c59ab055a8d3de40eaeb215c7b1922664b5ac049d849fb3346f81431e77f",
+            )
+            .unwrap(),
+        );
+        assert_eq!(assets, vec![expected_asset]);
+    }
+
+    #[test]
+    fn test_all_assets_sh_sortedmulti() {
+        let keys = vec![
+            "0360eabc52e04f70c89e944f379895cdff28fed60849afe7736815c091765afb3c",
+            "03a80a24196e66ccf6bca6e6f96633bb629ec702acd76b074de10922b0cf41cc81",
+        ];
+
+        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(&format!(
+            "sh(sortedmulti(1,{},{}))",
+            keys[0], keys[1]
+        ))
+        .unwrap();
+
+        let assets = descriptor.all_assets().unwrap();
+
+        let mut expected_assets: Vec<Assets> = Vec::new();
+
+        let mut asset1 = Assets::new();
+        asset1 = asset1.add(DescriptorPublicKey::from_str(keys[0]).unwrap());
+        expected_assets.push(asset1);
+
+        let mut asset2 = Assets::new();
+        asset2 = asset2.add(DescriptorPublicKey::from_str(keys[1]).unwrap());
+        expected_assets.push(asset2);
+
+        for expected_asset in &expected_assets {
+            assert!(assets.contains(expected_asset));
+        }
+    }
+
+    #[test]
+    fn test_all_assets_taproot() {
+        let x_only_key = bitcoin::key::XOnlyPublicKey::from_str(
+            "015e4cb53458bf813db8c79968e76e10d13ed6426a23fa71c2f41ba021c2a7ab",
+        )
+        .unwrap();
+        let descriptor =
+            Descriptor::from_str(&format!("tr({},pk({}))", x_only_key, x_only_key)).unwrap();
+        let assets = descriptor.all_assets().unwrap();
+        let mut expected_assets: Vec<Assets> = Vec::new();
+        let mut asset_1 = Assets::new();
+        asset_1 = asset_1.add(
+            DescriptorPublicKey::from_str(
+                "015e4cb53458bf813db8c79968e76e10d13ed6426a23fa71c2f41ba021c2a7ab",
+            )
+            .unwrap(),
+        );
+        expected_assets.push(asset_1);
+        assert_eq!(assets, expected_assets);
+    }
 }
diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs
index 48deb63e0..20be1bb92 100644
--- a/src/descriptor/tr.rs
+++ b/src/descriptor/tr.rs
@@ -15,14 +15,14 @@ use crate::descriptor::DefiniteDescriptorKey;
 use crate::expression::{self, FromTree};
 use crate::miniscript::satisfy::{Placeholder, Satisfaction, SchnorrSigType, Witness};
 use crate::miniscript::Miniscript;
-use crate::plan::AssetProvider;
+use crate::plan::{AssetProvider, Assets};
 use crate::policy::semantic::Policy;
 use crate::policy::Liftable;
 use crate::prelude::*;
 use crate::util::{varint_len, witness_size};
 use crate::{
-    errstr, Error, ForEachKey, MiniscriptKey, Satisfier, ScriptContext, Tap, ToPublicKey,
-    TranslateErr, TranslatePk, Translator,
+    errstr, DescriptorPublicKey, Error, ForEachKey, MiniscriptKey, Satisfier, ScriptContext, Tap,
+    ToPublicKey, TranslateErr, TranslatePk, Translator,
 };
 
 /// A Taproot Tree representation.
@@ -153,6 +153,33 @@ impl<Pk: MiniscriptKey> TapTree<Pk> {
     }
 }
 
+impl TapTree<DescriptorPublicKey> {
+    /// Get all possible assets for Taptree
+    pub fn all_assets(&self) -> Vec<Assets> {
+        match self {
+            TapTree::Tree { left, right, height: _ } => {
+                let mut a = left.all_assets();
+                let b = right.all_assets();
+                a.extend(b);
+                a
+            }
+            TapTree::Leaf(k) => k.all_assets(),
+        }
+    }
+
+    /// Get total possible assets for TapTree
+    pub fn count_assets(&self) -> u32 {
+        match self {
+            TapTree::Tree { left, right, height: _ } => {
+                let a = left.count_assets();
+                let b = right.count_assets();
+                a + b
+            }
+            TapTree::Leaf(k) => k.count_assets(),
+        }
+    }
+}
+
 impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
diff --git a/src/lib.rs b/src/lib.rs
index 7b798915e..14edbf90e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -501,12 +501,17 @@ pub enum Error {
     /// At least two BIP389 key expressions in the descriptor contain tuples of
     /// derivation indexes of different lengths.
     MultipathDescLenMismatch,
+    /// Cannot get assets for this large descriptor. Exceeds 1000 assets.
+    MaxAssetThresholdExceeded,
 }
 
 // https://github.com/sipa/miniscript/pull/5 for discussion on this number
 const MAX_RECURSION_DEPTH: u32 = 402;
 // https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
 const MAX_SCRIPT_SIZE: u32 = 10000;
+// For the planning module we are considering that total possible ways to spend
+// should be less than 1000
+const MAX_ASSET_THRESHOLD: u32 = 1000;
 
 impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -577,6 +582,7 @@ impl fmt::Display for Error {
             Error::TrNoScriptCode => write!(f, "No script code for Tr descriptors"),
             Error::TrNoExplicitScript => write!(f, "No script code for Tr descriptors"),
             Error::MultipathDescLenMismatch => write!(f, "At least two BIP389 key expressions in the descriptor contain tuples of derivation indexes of different lengths"),
+            Error::MaxAssetThresholdExceeded => write!(f,"Cannot plan descriptors having more than 1000 possible spend paths."),
         }
     }
 }
@@ -619,6 +625,7 @@ impl error::Error for Error {
             | TrNoScriptCode
             | TrNoExplicitScript
             | MultipathDescLenMismatch => None,
+            MaxAssetThresholdExceeded => None,
             Script(e) => Some(e),
             AddrError(e) => Some(e),
             BadPubkey(e) => Some(e),
diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs
index b272830e1..566f2d651 100644
--- a/src/miniscript/astelem.rs
+++ b/src/miniscript/astelem.rs
@@ -17,10 +17,12 @@ use sync::Arc;
 use crate::miniscript::context::SigType;
 use crate::miniscript::types::{self, Property};
 use crate::miniscript::ScriptContext;
+use crate::plan::Assets;
 use crate::prelude::*;
-use crate::util::MsKeyBuilder;
+use crate::util::{asset_combination, get_combinations_product, k_of_n, MsKeyBuilder};
 use crate::{
-    errstr, expression, AbsLockTime, Error, Miniscript, MiniscriptKey, Terminal, ToPublicKey,
+    errstr, expression, AbsLockTime, DescriptorPublicKey, Error, Miniscript, MiniscriptKey,
+    Terminal, ToPublicKey,
 };
 
 impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
@@ -593,3 +595,238 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
         }
     }
 }
+
+impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
+    /// Count total possible assets
+    pub fn count_assets(&self) -> u32 {
+        match self {
+            Terminal::True => 0,
+            Terminal::False => 0,
+            Terminal::PkK(_) => 1,
+            Terminal::PkH(_) => 1,
+            Terminal::RawPkH(_) => 1,
+            Terminal::After(_) => 0,
+            Terminal::Older(_) => 0,
+            Terminal::Sha256(_) => 1,
+            Terminal::Hash256(_) => 1,
+            Terminal::Ripemd160(_) => 1,
+            Terminal::Hash160(_) => 1,
+            Terminal::Alt(k) => k.count_assets(),
+            Terminal::Swap(k) => k.count_assets(),
+            Terminal::Check(k) => k.count_assets(),
+            Terminal::DupIf(k) => k.count_assets(),
+            Terminal::Verify(k) => k.count_assets(),
+            Terminal::NonZero(k) => k.count_assets(),
+            Terminal::ZeroNotEqual(k) => k.count_assets(),
+            Terminal::AndV(left, right) | Terminal::AndB(left, right) => {
+                let left_count = left.count_assets();
+                let right_count = right.count_assets();
+                left_count * right_count
+            }
+            Terminal::AndOr(a, b, c) => {
+                let a = a.count_assets();
+                let b = b.count_assets();
+                let c = c.count_assets();
+                (a * b) + c
+            }
+            Terminal::OrB(left, right)
+            | Terminal::OrC(left, right)
+            | Terminal::OrD(left, right)
+            | Terminal::OrI(left, right) => {
+                let left_count = left.count_assets();
+                let right_count = right.count_assets();
+                left_count + right_count
+            }
+            Terminal::Thresh(k, ms_v) => {
+                let mut count_array = Vec::new();
+                for ms in ms_v {
+                    count_array.push(ms.count_assets());
+                }
+                let products = get_combinations_product(&count_array, *k as u32);
+                let mut total_count: u32 = 0;
+                for product in products {
+                    total_count += product;
+                }
+                total_count
+            }
+            Terminal::Multi(k, dpk) | Terminal::MultiA(k, dpk) => {
+                let k: u32 = *k as u32;
+                let n: u32 = dpk.len() as u32;
+                k_of_n(k, n).unwrap()
+            }
+        }
+    }
+
+    /// Retrieve the assets associated with the type of miniscript element.
+    pub fn all_assets(&self) -> Vec<Assets> {
+        match self {
+            Terminal::True => vec![Assets::new()],
+            Terminal::False => Vec::new(),
+            Terminal::PkK(k) => {
+                let mut asset = Assets::new();
+                asset = asset.add(k.clone());
+                vec![asset]
+            }
+            Terminal::PkH(k) => {
+                let mut asset = Assets::new();
+                asset = asset.add(k.clone());
+                vec![asset]
+            }
+            Terminal::RawPkH(k) => {
+                let mut asset = Assets::new();
+                asset = asset.add(k.clone());
+                vec![asset]
+            }
+            Terminal::After(k) => {
+                let mut asset = Assets::new();
+                asset.absolute_timelock = Some(k.clone().into());
+                vec![asset]
+            }
+            Terminal::Older(k) => {
+                let mut asset = Assets::new();
+                asset.relative_timelock = Some(k.clone());
+                vec![asset]
+            }
+            Terminal::Sha256(k) => {
+                let mut asset = Assets::new();
+                asset = asset.add(k.clone());
+                vec![asset]
+            }
+            Terminal::Hash256(k) => {
+                let mut asset = Assets::new();
+                asset = asset.add(k.clone());
+                vec![asset]
+            }
+            Terminal::Ripemd160(k) => {
+                let mut asset = Assets::new();
+                asset = asset.add(k.clone());
+                vec![asset]
+            }
+            Terminal::Hash160(k) => {
+                let mut asset = Assets::new();
+                asset = asset.add(k.clone());
+                vec![asset]
+            }
+            Terminal::Alt(k) => k.all_assets(),
+            Terminal::Swap(k) => k.all_assets(),
+            Terminal::Check(k) => k.all_assets(),
+            Terminal::DupIf(k) => k.all_assets(),
+            Terminal::Verify(k) => k.all_assets(),
+            Terminal::NonZero(k) => k.all_assets(),
+            Terminal::ZeroNotEqual(k) => k.all_assets(),
+            Terminal::AndB(left, right) | Terminal::AndV(left, right) => {
+                let a = left.all_assets();
+                let b = right.all_assets();
+                let result: Vec<Assets> = a
+                    .into_iter()
+                    .flat_map(|x| {
+                        b.clone().into_iter().map(move |y| {
+                            let mut new_asset = Assets::new();
+                            new_asset = new_asset.add(x.clone());
+                            new_asset = new_asset.add(y.clone());
+                            new_asset
+                        })
+                    })
+                    .collect();
+                result
+            }
+            Terminal::AndOr(a, b, c) => {
+                let a = a.all_assets();
+                let b = b.all_assets();
+                let mut c = c.all_assets();
+                let and: Vec<Assets> = a
+                    .into_iter()
+                    .flat_map(|x| {
+                        b.clone().into_iter().map(move |y| {
+                            let mut new_asset = Assets::new();
+                            new_asset = new_asset.add(x.clone());
+                            new_asset = new_asset.add(y.clone());
+                            new_asset
+                        })
+                    })
+                    .collect();
+                c.extend(and);
+                c
+            }
+            Terminal::OrB(left, right)
+            | Terminal::OrC(left, right)
+            | Terminal::OrD(left, right)
+            | Terminal::OrI(left, right) => {
+                let mut a = left.all_assets();
+                let b = right.all_assets();
+                a.extend(b);
+                a
+            }
+            Terminal::Thresh(k, ms) => {
+                // In order to understand working of below code consider k of n as 2 of 3 thresh policy
+                // Eg : thresh(2,ms(A),ms(B),ms(C)) Here ms(A),ms(B) and ms(C) are miniscript policies
+                // k = 2
+                // ms = [ms(A),ms(B),ms(C)];
+                // We would consider the possible combinations of k policies into the ms_v
+                // here k=2 so all possible combinations of 2.
+                // ms_v = [[ms(A),ms(B)],[ms(A),ms(C)],[ms(B),ms(C)]]
+                // Between each set of combination we would need to do an OR
+                // (i.e ms_v[0] OR ms_v[1] OR ms_v[3])
+                // Now inside of each policy combination we need to have AND
+                // Eg : ms_v[0] = [ms(A),ms(B)] so here -> ms(A) AND ms(B)
+
+                let ms_v = Self::get_ms_combination_thresh(*k, ms);
+                let mut result = Vec::new();
+                for ms in ms_v {
+                    // AND between each miniscript policy
+                    let mut and: Vec<Assets> = Vec::new();
+                    if let Some(first_assets) = ms.first() {
+                        and = first_assets.all_assets().clone();
+                    }
+                    for i in ms.iter().skip(1) {
+                        let i_assets = i.all_assets();
+                        and = and
+                            .iter()
+                            .flat_map(|x| {
+                                i_assets.iter().map(move |y| {
+                                    let mut new_asset = x.clone();
+                                    new_asset = new_asset.add(y.clone());
+                                    new_asset
+                                })
+                            })
+                            .collect();
+                    }
+                    // OR of possible combinations of k miniscript policies.
+                    result.extend(and.clone());
+                }
+                result
+            }
+            Terminal::Multi(k, dpk_v) | Terminal::MultiA(k, dpk_v) => asset_combination(*k, dpk_v),
+        }
+    }
+
+    // Helper to get all combinations of K policies of N for thresh
+    fn get_ms_combination_thresh(
+        k: usize,
+        ms: &Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>,
+    ) -> Vec<Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>> {
+        let mut result = Vec::new();
+        let mut current_combination = Vec::new();
+        Self::combine_ms(0, &mut current_combination, &mut result, ms, k);
+        result
+    }
+
+    // combine K policies of N for thresh
+    fn combine_ms(
+        start: usize,
+        current_combination: &mut Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>,
+        result: &mut Vec<Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>>,
+        ms: &Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>,
+        k: usize,
+    ) {
+        if current_combination.len() == k {
+            result.push(current_combination.clone());
+            return;
+        }
+        for i in start..ms.len() {
+            current_combination.push(ms[i].clone());
+            Self::combine_ms(i + 1, current_combination, result, ms, k);
+            current_combination.truncate(current_combination.len() - 1);
+        }
+    }
+}
diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs
index fa75a712c..d6bbb07ae 100644
--- a/src/miniscript/mod.rs
+++ b/src/miniscript/mod.rs
@@ -22,8 +22,9 @@ use bitcoin::taproot::{LeafVersion, TapLeafHash};
 use self::analyzable::ExtParams;
 pub use self::context::{BareCtx, Legacy, Segwitv0, Tap};
 use crate::iter::TreeLike;
+use crate::plan::Assets;
 use crate::prelude::*;
-use crate::{script_num_size, TranslateErr};
+use crate::{script_num_size, DescriptorPublicKey, TranslateErr};
 
 pub mod analyzable;
 pub mod astelem;
@@ -385,6 +386,14 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Display for Miniscript<Pk, Ctx>
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.node) }
 }
 
+impl<Ctx: ScriptContext> Miniscript<DescriptorPublicKey, Ctx> {
+    /// Get all possible asset for a given node of Miniscript AST
+    pub fn all_assets(&self) -> Vec<Assets> { self.node.all_assets() }
+
+    /// Get the total number of assets possible
+    pub fn count_assets(&self) -> u32 { self.node.count_assets() }
+}
+
 impl<Pk: MiniscriptKey, Ctx: ScriptContext> ForEachKey<Pk> for Miniscript<Pk, Ctx> {
     fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool {
         for ms in self.pre_order_iter() {
@@ -610,10 +619,11 @@ mod tests {
     use super::{Miniscript, ScriptContext, Segwitv0, Tap};
     use crate::miniscript::types::{self, ExtData, Property, Type};
     use crate::miniscript::Terminal;
+    use crate::plan::Assets;
     use crate::policy::Liftable;
     use crate::prelude::*;
     use crate::test_utils::{StrKeyTranslator, StrXOnlyKeyTranslator};
-    use crate::{hex_script, ExtParams, Satisfier, ToPublicKey, TranslatePk};
+    use crate::{hex_script, DescriptorPublicKey, ExtParams, Satisfier, ToPublicKey, TranslatePk};
 
     type Segwitv0Script = Miniscript<bitcoin::PublicKey, Segwitv0>;
     type Tapscript = Miniscript<bitcoin::secp256k1::XOnlyPublicKey, Tap>;
@@ -1351,4 +1361,139 @@ mod tests {
             assert_eq!(template.relative_timelock, relative_timelock, "{}", ms_str);
         }
     }
+
+    #[test]
+    fn test_all_assets_and() {
+        let keys = vec![
+            "02638737cb676ca8851ac3e2c155e16cf9186d8d576e5670d76d49f8840113d078",
+            "02b33eeea5cd309376cf82914dce386f26459a07354add732069b90abd907674cb",
+            "02722c78fed469dd77df4a2c92c5bf4ddfa583fad30a1b7993488530d2d097393c",
+        ];
+
+        let ms = Miniscript::<DescriptorPublicKey, Segwitv0>::from_str(&format!(
+            "and_v(v:pk({}),pk({}))",
+            keys[0], keys[1]
+        ))
+        .unwrap();
+
+        // Getting the assets from the all_assets method
+        let assets = ms.all_assets();
+
+        let mut expected_asset = Assets::new();
+        expected_asset = expected_asset.add(DescriptorPublicKey::from_str(keys[0]).unwrap()); // A
+        expected_asset = expected_asset.add(DescriptorPublicKey::from_str(keys[1]).unwrap()); // B
+
+        assert_eq!(assets, vec![expected_asset]);
+    }
+
+    #[test]
+    fn test_all_assets_multi() {
+        let keys = vec![
+            "02638737cb676ca8851ac3e2c155e16cf9186d8d576e5670d76d49f8840113d078",
+            "02b33eeea5cd309376cf82914dce386f26459a07354add732069b90abd907674cb",
+            "02722c78fed469dd77df4a2c92c5bf4ddfa583fad30a1b7993488530d2d097393c",
+        ];
+
+        let ms = Miniscript::<DescriptorPublicKey, Segwitv0>::from_str(&format!(
+            "multi(2,{},{},{})",
+            keys[0], keys[1], keys[2]
+        ))
+        .unwrap();
+
+        // Getting the assets from the all_assets method
+        let assets = ms.all_assets();
+
+        let mut expected_assets: Vec<Assets> = Vec::new();
+
+        let mut assets_1 = Assets::new();
+        assets_1 = assets_1.add(DescriptorPublicKey::from_str(keys[0]).unwrap()); // A
+        assets_1 = assets_1.add(DescriptorPublicKey::from_str(keys[1]).unwrap()); // B
+        expected_assets.push(assets_1);
+
+        let mut assets_2 = Assets::new();
+        assets_2 = assets_2.add(DescriptorPublicKey::from_str(keys[0]).unwrap()); // A
+        assets_2 = assets_2.add(DescriptorPublicKey::from_str(keys[2]).unwrap()); // C
+        expected_assets.push(assets_2);
+
+        let mut assets_3 = Assets::new();
+        assets_3 = assets_3.add(DescriptorPublicKey::from_str(keys[1]).unwrap()); // B
+        assets_3 = assets_3.add(DescriptorPublicKey::from_str(keys[2]).unwrap()); // C
+        expected_assets.push(assets_3);
+
+        for expected_asset in &expected_assets {
+            assert!(assets.contains(expected_asset));
+        }
+    }
+
+    #[test]
+    fn test_all_assets_or() {
+        let keys = vec![
+            "02638737cb676ca8851ac3e2c155e16cf9186d8d576e5670d76d49f8840113d078",
+            "02b33eeea5cd309376cf82914dce386f26459a07354add732069b90abd907674cb",
+        ];
+
+        let ms = Miniscript::<DescriptorPublicKey, Segwitv0>::from_str(&format!(
+            "or_b(pk({}),s:pk({}))",
+            keys[0], keys[1]
+        ))
+        .unwrap();
+
+        // Getting the assets from the all_assets method
+        let assets = ms.all_assets();
+
+        let mut expected_assets: Vec<Assets> = Vec::new();
+
+        let mut asset1 = Assets::new();
+        asset1 = asset1.add(DescriptorPublicKey::from_str(keys[0]).unwrap()); // A
+        expected_assets.push(asset1);
+
+        let mut asset2 = Assets::new();
+        asset2 = asset2.add(DescriptorPublicKey::from_str(keys[1]).unwrap()); // B
+        expected_assets.push(asset2);
+
+        // Check that all received assets are as expected.
+        for expected_asset in &expected_assets {
+            assert!(assets.contains(expected_asset));
+        }
+    }
+
+    #[test]
+    fn test_all_assets_thresh() {
+        let keys = vec![
+            "02638737cb676ca8851ac3e2c155e16cf9186d8d576e5670d76d49f8840113d078",
+            "02b33eeea5cd309376cf82914dce386f26459a07354add732069b90abd907674cb",
+            "02722c78fed469dd77df4a2c92c5bf4ddfa583fad30a1b7993488530d2d097393c",
+        ];
+
+        let ms = Miniscript::<DescriptorPublicKey, Segwitv0>::from_str(&format!(
+            "thresh(2,pk({}),a:pk({}),a:pk({}))",
+            keys[0], keys[1], keys[2]
+        ))
+        .unwrap();
+
+        // Getting the assets from the all_assets method
+        let assets = ms.all_assets();
+
+        let mut expected_assets: Vec<Assets> = Vec::new();
+
+        let mut assets_1 = Assets::new();
+        assets_1 = assets_1.add(DescriptorPublicKey::from_str(keys[0]).unwrap()); // A
+        assets_1 = assets_1.add(DescriptorPublicKey::from_str(keys[1]).unwrap()); // B
+        expected_assets.push(assets_1);
+
+        let mut assets_2 = Assets::new();
+        assets_2 = assets_2.add(DescriptorPublicKey::from_str(keys[0]).unwrap()); // A
+        assets_2 = assets_2.add(DescriptorPublicKey::from_str(keys[2]).unwrap()); // C
+        expected_assets.push(assets_2);
+
+        let mut assets_3 = Assets::new();
+        assets_3 = assets_3.add(DescriptorPublicKey::from_str(keys[1]).unwrap()); // B
+        assets_3 = assets_3.add(DescriptorPublicKey::from_str(keys[2]).unwrap()); // C
+        expected_assets.push(assets_3);
+
+        // Check that all received assets are as expected.
+        for expected_asset in &expected_assets {
+            assert!(assets.contains(expected_asset));
+        }
+    }
 }
diff --git a/src/plan.rs b/src/plan.rs
index 32e9aa75d..a2cfe1df9 100644
--- a/src/plan.rs
+++ b/src/plan.rs
@@ -504,7 +504,7 @@ impl TaprootAvailableLeaves {
 }
 
 /// The Assets we can use to satisfy a particular spending path
-#[derive(Debug, Default)]
+#[derive(Debug, Default, Clone, PartialEq)]
 pub struct Assets {
     /// Keys the user can sign for, and how. A pair `(fingerprint, derivation_path)` is
     /// provided, meaning that the user can sign using the key with `fingerprint`,
diff --git a/src/util.rs b/src/util.rs
index 11643b643..d963c42e2 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -8,8 +8,11 @@ use bitcoin::PubkeyHash;
 
 use crate::miniscript::context;
 use crate::miniscript::satisfy::Placeholder;
+use crate::plan::Assets;
 use crate::prelude::*;
-use crate::{MiniscriptKey, ScriptContext, ToPublicKey};
+use crate::{
+    DescriptorPublicKey, Error, MiniscriptKey, ScriptContext, ToPublicKey, MAX_ASSET_THRESHOLD,
+};
 pub(crate) fn varint_len(n: usize) -> usize { bitcoin::VarInt(n as u64).len() }
 
 pub(crate) trait ItemSize {
@@ -55,7 +58,7 @@ pub(crate) fn witness_to_scriptsig(witness: &[Vec<u8>]) -> ScriptBuf {
         } else {
             let push = <&PushBytes>::try_from(wit.as_slice())
                 .expect("All pushes in miniscript are <73 bytes");
-            b = b.push_slice(push)
+            b = b.push_slice(push);
         }
     }
     b.into_script()
@@ -101,3 +104,77 @@ impl MsKeyBuilder for script::Builder {
         }
     }
 }
+
+// Helper to get all possible pairs of K of N assets
+pub fn asset_combination(k: usize, dpk_v: &Vec<DescriptorPublicKey>) -> Vec<Assets> {
+    let mut all_assets: Vec<Assets> = Vec::new();
+    let current_assets = Assets::new();
+    combine_assets(k, dpk_v, 0, current_assets, &mut all_assets);
+    all_assets
+}
+
+// Combine K of N assets
+pub fn combine_assets(
+    k: usize,
+    dpk_v: &[DescriptorPublicKey],
+    index: usize,
+    current_assets: Assets,
+    all_assets: &mut Vec<Assets>,
+) {
+    if k == 0 {
+        all_assets.push(current_assets);
+        return;
+    }
+    if index >= dpk_v.len() {
+        return;
+    }
+    combine_assets(k, dpk_v, index + 1, current_assets.clone(), all_assets);
+    let mut new_asset = current_assets;
+    new_asset = new_asset.add(dpk_v[index].clone());
+    combine_assets(k - 1, dpk_v, index + 1, new_asset, all_assets)
+}
+
+// Do product of K combinations
+pub fn get_combinations_product(values: &[u32], k: u32) -> Vec<u32> {
+    let mut products = Vec::new();
+    let n = values.len();
+
+    if k == 0 {
+        return vec![1]; // Empty combination has a product of 1
+    }
+
+    // Using bitwise operations to generate combinations
+    let max_combinations = 1u32 << n;
+    for combination_bits in 1..max_combinations {
+        if (combination_bits.count_ones() as usize) == (k as usize) {
+            let mut product = 1;
+            for i in 0..n {
+                if (combination_bits & (1u32 << i)) != 0 {
+                    product *= values[i];
+                }
+            }
+            products.push(product);
+        }
+    }
+
+    products
+}
+
+// ways to select k things out of n
+pub fn k_of_n(k: u32, n: u32) -> Result<u32, Error> {
+    let mut k = k;
+    if k > n - k {
+        k = n - k;
+    }
+
+    let mut result = 1;
+    for i in 0..k {
+        result *= n - i;
+        result /= i + 1;
+        if result > MAX_ASSET_THRESHOLD.into() {
+            return Err(Error::MaxAssetThresholdExceeded);
+        }
+    }
+
+    Ok(result)
+}