@@ -597,6 +597,93 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
597597}
598598
599599impl < Ctx : ScriptContext > Terminal < DescriptorPublicKey , Ctx > {
600+ /// Count total possible assets
601+ pub fn count_assets ( & self ) -> u64 {
602+ match self {
603+ Terminal :: True => 0 ,
604+ Terminal :: False => 0 ,
605+ Terminal :: PkK ( _) => 1 ,
606+ Terminal :: PkH ( _) => 1 ,
607+ Terminal :: RawPkH ( _) => 1 ,
608+ // What happens to timelocks ? for both the assets and the count.
609+ Terminal :: After ( _) => 0 ,
610+ Terminal :: Older ( _) => 0 ,
611+ Terminal :: Sha256 ( _) => 1 ,
612+ Terminal :: Hash256 ( _) => 1 ,
613+ Terminal :: Ripemd160 ( _) => 1 ,
614+ Terminal :: Hash160 ( _) => 1 ,
615+ Terminal :: Alt ( k) => k. count_assets ( ) ,
616+ Terminal :: Swap ( k) => k. count_assets ( ) ,
617+ Terminal :: Check ( k) => k. count_assets ( ) ,
618+ Terminal :: DupIf ( k) => k. count_assets ( ) ,
619+ Terminal :: Verify ( k) => k. count_assets ( ) ,
620+ Terminal :: NonZero ( k) => k. count_assets ( ) ,
621+ Terminal :: ZeroNotEqual ( k) => k. count_assets ( ) ,
622+ Terminal :: AndV ( left, right) => {
623+ let left_count = left. count_assets ( ) ;
624+ let right_count = right. count_assets ( ) ;
625+ left_count * right_count
626+ }
627+ Terminal :: AndB ( left, right) => {
628+ let left_count = left. count_assets ( ) ;
629+ let right_count = right. count_assets ( ) ;
630+ left_count * right_count
631+ }
632+ Terminal :: AndOr ( a, b, c) => {
633+ let a = a. count_assets ( ) ;
634+ let b = b. count_assets ( ) ;
635+ let c = c. count_assets ( ) ;
636+ ( a * b) + c
637+ }
638+ Terminal :: OrB ( left, right) => {
639+ let left_count = left. count_assets ( ) ;
640+ let right_count = right. count_assets ( ) ;
641+ left_count + right_count
642+ }
643+ Terminal :: OrD ( left, right) => {
644+ let left_count = left. count_assets ( ) ;
645+ let right_count = right. count_assets ( ) ;
646+ left_count + right_count
647+ }
648+ Terminal :: OrC ( left, right) => {
649+ let left_count = left. count_assets ( ) ;
650+ let right_count = right. count_assets ( ) ;
651+ left_count + right_count
652+ }
653+ Terminal :: OrI ( left, right) => {
654+ let left_count = left. count_assets ( ) ;
655+ let right_count = right. count_assets ( ) ;
656+ left_count + right_count
657+ }
658+ Terminal :: Thresh ( k, ms_v) => {
659+ // k = 2, n = ms_v.len()
660+ // ms_v = [ms(A),ms(B),ms(C)];
661+ // Assume count array as [5,7,8] and k=2
662+ // get_combinations_product gives [5*7,5*8,7*8] = [35,40,56]
663+ let mut count_array = Vec :: new ( ) ;
664+ for ms in ms_v {
665+ count_array. push ( ms. count_assets ( ) ) ;
666+ }
667+ let products = Self :: get_combinations_product ( & count_array, * k as u64 ) ;
668+ let mut total_count: u64 = 0 ;
669+ for product in products {
670+ total_count += product;
671+ }
672+ total_count
673+ }
674+ Terminal :: Multi ( k, dpk) => {
675+ let k: u64 = * k as u64 ;
676+ let n: u64 = dpk. len ( ) as u64 ;
677+ Self :: k_of_n ( k, n)
678+ }
679+ Terminal :: MultiA ( k, dpk) => {
680+ let k: u64 = * k as u64 ;
681+ let n: u64 = dpk. len ( ) as u64 ;
682+ Self :: k_of_n ( k, n)
683+ }
684+ }
685+ }
686+
600687 /// Retrieve the assets associated with the type of miniscript element.
601688 pub fn get_all_assets ( & self ) -> Vec < Assets > {
602689 match self {
@@ -824,4 +911,38 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
824911 current_combination. truncate ( current_combination. len ( ) - 1 ) ;
825912 }
826913 }
914+
915+ // Do product of K combinations
916+ fn get_combinations_product ( values : & [ u64 ] , k : u64 ) -> Vec < u64 > {
917+ let mut products = Vec :: new ( ) ;
918+ let n = values. len ( ) ;
919+
920+ if k == 0 {
921+ return vec ! [ 1 ] ; // Empty combination has a product of 1
922+ }
923+
924+ // Using bitwise operations to generate combinations
925+ let max_combinations = 1u32 << n;
926+ for combination_bits in 1 ..max_combinations {
927+ if combination_bits. count_ones ( ) as usize == k as usize {
928+ let mut product = 1 ;
929+ for i in 0 ..n {
930+ if combination_bits & ( 1u32 << i) != 0 {
931+ product *= values[ i] ;
932+ }
933+ }
934+ products. push ( product) ;
935+ }
936+ }
937+
938+ products
939+ }
940+
941+ // ways to select k things out of n
942+ fn k_of_n ( k : u64 , n : u64 ) -> u64 {
943+ if k == 0 || k == n {
944+ return 1 ;
945+ }
946+ Self :: k_of_n ( k - 1 , n - 1 ) + Self :: k_of_n ( k, n - 1 )
947+ }
827948}
0 commit comments