@@ -598,6 +598,93 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
598
598
}
599
599
600
600
impl < 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
+
601
688
/// Retrieve the assets associated with the type of miniscript element.
602
689
pub fn get_all_assets ( & self ) -> Vec < Assets > {
603
690
match self {
@@ -825,4 +912,38 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
825
912
current_combination. truncate ( current_combination. len ( ) - 1 ) ;
826
913
}
827
914
}
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
+ }
828
949
}
0 commit comments