Skip to content

Commit 37d6a3d

Browse files
committed
count_assets method for total ways to obtain assets
Signed-off-by: Harshil Jani <[email protected]>
1 parent bf4ff5c commit 37d6a3d

File tree

3 files changed

+62
-101
lines changed

3 files changed

+62
-101
lines changed

src/descriptor/mod.rs

+7-15
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::miniscript::decode::Terminal;
2525
use crate::miniscript::{satisfy, Legacy, Miniscript, Segwitv0};
2626
use crate::plan::{AssetProvider, Assets, Plan};
2727
use crate::prelude::*;
28-
use crate::util::get_asset_combination;
28+
use crate::util::{asset_combination, k_of_n};
2929
use crate::{
3030
expression, hash256, BareCtx, Error, ForEachKey, MiniscriptKey, Satisfier, ToPublicKey,
3131
TranslateErr, TranslatePk, Translator,
@@ -581,23 +581,23 @@ impl Descriptor<DescriptorPublicKey> {
581581
WshInner::SortedMulti(k) => {
582582
let n = k.pks.len() as u64;
583583
let k = k.k as u64;
584-
Self::k_of_n(k, n)
584+
k_of_n(k, n)
585585
}
586586
WshInner::Ms(k) => k.count_assets(),
587587
},
588588
ShInner::Wpkh(_) => 1,
589589
ShInner::SortedMulti(k) => {
590590
let n = k.clone().pks.len() as u64;
591591
let k = k.clone().k as u64;
592-
Self::k_of_n(k, n)
592+
k_of_n(k, n)
593593
}
594594
ShInner::Ms(k) => k.count_assets(),
595595
},
596596
Descriptor::Wsh(k) => match k.as_inner() {
597597
WshInner::SortedMulti(k) => {
598598
let n = k.clone().pks.len() as u64;
599599
let k = k.clone().k as u64;
600-
Self::k_of_n(k, n)
600+
k_of_n(k, n)
601601
}
602602
WshInner::Ms(k) => k.count_assets(),
603603
},
@@ -634,7 +634,7 @@ impl Descriptor<DescriptorPublicKey> {
634634
WshInner::SortedMulti(k) => {
635635
let dpk_v = k.clone().pks;
636636
let k = k.clone().k;
637-
Ok(get_asset_combination(k, &dpk_v))
637+
Ok(asset_combination(k, &dpk_v))
638638
}
639639
WshInner::Ms(k) => Ok(k.all_assets()),
640640
},
@@ -646,15 +646,15 @@ impl Descriptor<DescriptorPublicKey> {
646646
ShInner::SortedMulti(k) => {
647647
let dpk_v = k.clone().pks;
648648
let k = k.clone().k;
649-
Ok(get_asset_combination(k, &dpk_v))
649+
Ok(asset_combination(k, &dpk_v))
650650
}
651651
ShInner::Ms(k) => Ok(k.all_assets()),
652652
},
653653
Descriptor::Wsh(k) => match k.as_inner() {
654654
WshInner::SortedMulti(k) => {
655655
let dpk_v = k.clone().pks;
656656
let k = k.clone().k;
657-
Ok(get_asset_combination(k, &dpk_v))
657+
Ok(asset_combination(k, &dpk_v))
658658
}
659659
WshInner::Ms(k) => {
660660
println!("{}", k);
@@ -677,14 +677,6 @@ impl Descriptor<DescriptorPublicKey> {
677677
}
678678
}
679679
}
680-
681-
// ways to select k things out of n
682-
fn k_of_n(k: u64, n: u64) -> u64 {
683-
if k == 0 || k == n {
684-
return 1;
685-
}
686-
Self::k_of_n(k - 1, n - 1) + Self::k_of_n(k - 1, n)
687-
}
688680
}
689681

690682
impl<P, Q> TranslatePk<P, Q> for Descriptor<P>

src/miniscript/astelem.rs

+18-83
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::miniscript::types::{self, Property};
1919
use crate::miniscript::ScriptContext;
2020
use crate::plan::Assets;
2121
use crate::prelude::*;
22-
use crate::util::{MsKeyBuilder, get_asset_combination};
22+
use crate::util::{asset_combination, get_combinations_product, k_of_n, MsKeyBuilder};
2323
use crate::{
2424
errstr, expression, AbsLockTime, DescriptorPublicKey, Error, Miniscript, MiniscriptKey,
2525
Terminal, ToPublicKey,
@@ -605,7 +605,6 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
605605
Terminal::PkK(_) => 1,
606606
Terminal::PkH(_) => 1,
607607
Terminal::RawPkH(_) => 1,
608-
// What happens to timelocks ? for both the assets and the count.
609608
Terminal::After(_) => 0,
610609
Terminal::Older(_) => 0,
611610
Terminal::Sha256(_) => 1,
@@ -619,12 +618,7 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
619618
Terminal::Verify(k) => k.count_assets(),
620619
Terminal::NonZero(k) => k.count_assets(),
621620
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) => {
621+
Terminal::AndV(left, right) | Terminal::AndB(left, right) => {
628622
let left_count = left.count_assets();
629623
let right_count = right.count_assets();
630624
left_count * right_count
@@ -635,51 +629,30 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
635629
let c = c.count_assets();
636630
(a * b) + c
637631
}
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) => {
632+
Terminal::OrB(left, right)
633+
| Terminal::OrC(left, right)
634+
| Terminal::OrD(left, right)
635+
| Terminal::OrI(left, right) => {
654636
let left_count = left.count_assets();
655637
let right_count = right.count_assets();
656638
left_count + right_count
657639
}
658640
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]
663641
let mut count_array = Vec::new();
664642
for ms in ms_v {
665643
count_array.push(ms.count_assets());
666644
}
667-
let products = Self::get_combinations_product(&count_array, *k as u64);
645+
let products = get_combinations_product(&count_array, *k as u64);
668646
let mut total_count: u64 = 0;
669647
for product in products {
670648
total_count += product;
671649
}
672650
total_count
673651
}
674-
Terminal::Multi(k, dpk) => {
652+
Terminal::Multi(k, dpk) | Terminal::MultiA(k, dpk) => {
675653
let k: u64 = *k as u64;
676654
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)
655+
k_of_n(k, n)
683656
}
684657
}
685658
}
@@ -741,9 +714,7 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
741714
Terminal::Verify(k) => k.all_assets(),
742715
Terminal::NonZero(k) => k.all_assets(),
743716
Terminal::ZeroNotEqual(k) => k.all_assets(),
744-
Terminal::AndB(left, right) |
745-
Terminal::AndV(left, right)
746-
=> {
717+
Terminal::AndB(left, right) | Terminal::AndV(left, right) => {
747718
let a = left.all_assets();
748719
let b = right.all_assets();
749720
let result: Vec<Assets> = a
@@ -777,11 +748,10 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
777748
c.extend(and);
778749
c
779750
}
780-
Terminal::OrB(left, right) |
781-
Terminal::OrC(left, right) |
782-
Terminal::OrD(left, right) |
783-
Terminal::OrI(left, right)
784-
=> {
751+
Terminal::OrB(left, right)
752+
| Terminal::OrC(left, right)
753+
| Terminal::OrD(left, right)
754+
| Terminal::OrI(left, right) => {
785755
let mut a = left.all_assets();
786756
let b = right.all_assets();
787757
a.extend(b);
@@ -792,14 +762,14 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
792762
// Eg : thresh(2,ms(A),ms(B),ms(C)) Here ms(A),ms(B) and ms(C) are miniscript policies
793763
// k = 2
794764
// ms = [ms(A),ms(B),ms(C)];
795-
// We would consider the possible combinations of k policies into the ms_v
765+
// We would consider the possible combinations of k policies into the ms_v
796766
// here k=2 so all possible combinations of 2.
797767
// ms_v = [[ms(A),ms(B)],[ms(A),ms(C)],[ms(B),ms(C)]]
798-
// Between each set of combination we would need to do an OR
768+
// Between each set of combination we would need to do an OR
799769
// (i.e ms_v[0] OR ms_v[1] OR ms_v[3])
800770
// Now inside of each policy combination we need to have AND
801771
// Eg : ms_v[0] = [ms(A),ms(B)] so here -> ms(A) AND ms(B)
802-
772+
803773
let ms_v = Self::get_ms_combination_thresh(*k, ms);
804774
let mut result = Vec::new();
805775
for ms in ms_v {
@@ -826,8 +796,7 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
826796
}
827797
result
828798
}
829-
Terminal::Multi(k, dpk_v) |
830-
Terminal::MultiA(k,dpk_v ) => get_asset_combination(*k, dpk_v),
799+
Terminal::Multi(k, dpk_v) | Terminal::MultiA(k, dpk_v) => asset_combination(*k, dpk_v),
831800
}
832801
}
833802

@@ -860,38 +829,4 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
860829
current_combination.truncate(current_combination.len() - 1);
861830
}
862831
}
863-
864-
// Do product of K combinations
865-
fn get_combinations_product(values: &[u64], k: u64) -> Vec<u64> {
866-
let mut products = Vec::new();
867-
let n = values.len();
868-
869-
if k == 0 {
870-
return vec![1]; // Empty combination has a product of 1
871-
}
872-
873-
// Using bitwise operations to generate combinations
874-
let max_combinations = 1u32 << n;
875-
for combination_bits in 1..max_combinations {
876-
if combination_bits.count_ones() as usize == k as usize {
877-
let mut product = 1;
878-
for i in 0..n {
879-
if combination_bits & (1u32 << i) != 0 {
880-
product *= values[i];
881-
}
882-
}
883-
products.push(product);
884-
}
885-
}
886-
887-
products
888-
}
889-
890-
// ways to select k things out of n
891-
fn k_of_n(k: u64, n: u64) -> u64 {
892-
if k == 0 || k == n {
893-
return 1;
894-
}
895-
Self::k_of_n(k - 1, n - 1) + Self::k_of_n(k, n - 1)
896-
}
897832
}

src/util.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use bitcoin::PubkeyHash;
99
use crate::miniscript::context;
1010
use crate::miniscript::satisfy::Placeholder;
1111
use crate::plan::Assets;
12-
use crate::{prelude::*, DescriptorPublicKey};
13-
use crate::{MiniscriptKey, ScriptContext, ToPublicKey};
12+
use crate::prelude::*;
13+
use crate::{DescriptorPublicKey, MiniscriptKey, ScriptContext, ToPublicKey};
1414
pub(crate) fn varint_len(n: usize) -> usize {
1515
bitcoin::VarInt(n as u64).len()
1616
}
@@ -108,7 +108,7 @@ impl MsKeyBuilder for script::Builder {
108108
}
109109

110110
// Helper to get all possible pairs of K of N assets
111-
pub fn get_asset_combination(k: usize, dpk_v: &Vec<DescriptorPublicKey>) -> Vec<Assets> {
111+
pub fn asset_combination(k: usize, dpk_v: &Vec<DescriptorPublicKey>) -> Vec<Assets> {
112112
let mut all_assets: Vec<Assets> = Vec::new();
113113
let current_assets = Assets::new();
114114
combine_assets(k, dpk_v, 0, current_assets, &mut all_assets);
@@ -136,3 +136,37 @@ pub fn combine_assets(
136136
println!("{:#?}", new_asset);
137137
combine_assets(k - 1, dpk_v, index + 1, new_asset, all_assets)
138138
}
139+
140+
// Do product of K combinations
141+
pub fn get_combinations_product(values: &[u64], k: u64) -> Vec<u64> {
142+
let mut products = Vec::new();
143+
let n = values.len();
144+
145+
if k == 0 {
146+
return vec![1]; // Empty combination has a product of 1
147+
}
148+
149+
// Using bitwise operations to generate combinations
150+
let max_combinations = 1u32 << n;
151+
for combination_bits in 1..max_combinations {
152+
if combination_bits.count_ones() as usize == k as usize {
153+
let mut product = 1;
154+
for i in 0..n {
155+
if combination_bits & (1u32 << i) != 0 {
156+
product *= values[i];
157+
}
158+
}
159+
products.push(product);
160+
}
161+
}
162+
163+
products
164+
}
165+
166+
// ways to select k things out of n
167+
pub fn k_of_n(k: u64, n: u64) -> u64 {
168+
if k == 0 || k == n {
169+
return 1;
170+
}
171+
k_of_n(k - 1, n - 1) + k_of_n(k, n - 1)
172+
}

0 commit comments

Comments
 (0)