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