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