@@ -20,20 +20,27 @@ use std::{error, fmt, str};
2020
2121use bitcoin:: hashes:: hex:: FromHex ;
2222use bitcoin:: hashes:: { hash160, ripemd160, sha256, sha256d} ;
23+ #[ cfg( feature = "compiler" ) ]
24+ use {
25+ crate :: descriptor:: TapTree ,
26+ crate :: miniscript:: ScriptContext ,
27+ crate :: policy:: compiler:: CompilerError ,
28+ crate :: policy:: compiler:: OrdF64 ,
29+ crate :: policy:: { compiler, Concrete , Liftable , Semantic } ,
30+ crate :: Descriptor ,
31+ crate :: Miniscript ,
32+ crate :: Tap ,
33+ std:: cmp:: Reverse ,
34+ std:: collections:: { BinaryHeap , HashMap } ,
35+ std:: sync:: Arc ,
36+ } ;
2337
2438use super :: ENTAILMENT_MAX_TERMINALS ;
2539use crate :: expression:: { self , FromTree } ;
2640use crate :: miniscript:: limits:: { HEIGHT_TIME_THRESHOLD , SEQUENCE_LOCKTIME_TYPE_FLAG } ;
2741use crate :: miniscript:: types:: extra_props:: TimeLockInfo ;
28- #[ cfg( feature = "compiler" ) ]
29- use crate :: miniscript:: ScriptContext ;
30- #[ cfg( feature = "compiler" ) ]
31- use crate :: policy:: compiler;
32- #[ cfg( feature = "compiler" ) ]
33- use crate :: policy:: compiler:: CompilerError ;
34- #[ cfg( feature = "compiler" ) ]
35- use crate :: Miniscript ;
3642use crate :: { errstr, Error , ForEach , ForEachKey , MiniscriptKey } ;
43+
3744/// Concrete policy which corresponds directly to a Miniscript structure,
3845/// and whose disjunctions are annotated with satisfaction probabilities
3946/// to assist the compiler
@@ -128,6 +135,136 @@ impl fmt::Display for PolicyError {
128135}
129136
130137impl < Pk : MiniscriptKey > Policy < Pk > {
138+ /// Flatten the [`Policy`] tree structure into a Vector of tuple `(leaf script, leaf probability)`
139+ /// with leaf probabilities corresponding to odds for sub-branch in the policy.
140+ /// We calculate the probability of selecting the sub-branch at every level and calculate the
141+ /// leaf probabilities as the probability of traversing through required branches to reach the
142+ /// leaf node, i.e. multiplication of the respective probabilities.
143+ ///
144+ /// For example, the policy tree: OR
145+ /// / \
146+ /// 2 1 odds
147+ /// / \
148+ /// A OR
149+ /// / \
150+ /// 3 1 odds
151+ /// / \
152+ /// B C
153+ ///
154+ /// gives the vector [(2/3, A), (1/3 * 3/4, B), (1/3 * 1/4, C)].
155+ #[ cfg( feature = "compiler" ) ]
156+ fn to_tapleaf_prob_vec ( & self , prob : f64 ) -> Vec < ( f64 , Policy < Pk > ) > {
157+ match * self {
158+ Policy :: Or ( ref subs) => {
159+ let total_odds: usize = subs. iter ( ) . map ( |( ref k, _) | k) . sum ( ) ;
160+ subs. iter ( )
161+ . map ( |( k, ref policy) | {
162+ policy. to_tapleaf_prob_vec ( prob * * k as f64 / total_odds as f64 )
163+ } )
164+ . flatten ( )
165+ . collect :: < Vec < _ > > ( )
166+ }
167+ Policy :: Threshold ( k, ref subs) if k == 1 => {
168+ let total_odds = subs. len ( ) ;
169+ subs. iter ( )
170+ . map ( |policy| policy. to_tapleaf_prob_vec ( prob / total_odds as f64 ) )
171+ . flatten ( )
172+ . collect :: < Vec < _ > > ( )
173+ }
174+ ref x => vec ! [ ( prob, x. clone( ) ) ] ,
175+ }
176+ }
177+
178+ /// Compile [`Policy::Or`] and [`Policy::Threshold`] according to odds
179+ #[ cfg( feature = "compiler" ) ]
180+ fn compile_tr_policy ( & self ) -> Result < TapTree < Pk > , Error > {
181+ let leaf_compilations: Vec < _ > = self
182+ . to_tapleaf_prob_vec ( 1.0 )
183+ . into_iter ( )
184+ . filter ( |x| x. 1 != Policy :: Unsatisfiable )
185+ . map ( |( prob, ref policy) | ( OrdF64 ( prob) , compiler:: best_compilation ( policy) . unwrap ( ) ) )
186+ . collect ( ) ;
187+ let taptree = with_huffman_tree :: < Pk > ( leaf_compilations) . unwrap ( ) ;
188+ Ok ( taptree)
189+ }
190+
191+ /// Extract the internal_key from policy tree.
192+ #[ cfg( feature = "compiler" ) ]
193+ fn extract_key ( self , unspendable_key : Option < Pk > ) -> Result < ( Pk , Policy < Pk > ) , Error > {
194+ let mut internal_key: Option < Pk > = None ;
195+ {
196+ let mut prob = 0. ;
197+ let semantic_policy = self . lift ( ) ?;
198+ let concrete_keys = self . keys ( ) ;
199+ let key_prob_map: HashMap < _ , _ > = self
200+ . to_tapleaf_prob_vec ( 1.0 )
201+ . into_iter ( )
202+ . filter ( |( _, ref pol) | match * pol {
203+ Concrete :: Key ( ..) => true ,
204+ _ => false ,
205+ } )
206+ . map ( |( prob, key) | ( key, prob) )
207+ . collect ( ) ;
208+
209+ for key in concrete_keys. into_iter ( ) {
210+ if semantic_policy
211+ . clone ( )
212+ . satisfy_constraint ( & Semantic :: KeyHash ( key. to_pubkeyhash ( ) ) , true )
213+ == Semantic :: Trivial
214+ {
215+ match key_prob_map. get ( & Concrete :: Key ( key. clone ( ) ) ) {
216+ Some ( val) => {
217+ if * val > prob {
218+ prob = * val;
219+ internal_key = Some ( key. clone ( ) ) ;
220+ }
221+ }
222+ None => return Err ( errstr ( "Key should have existed in the HashMap!" ) ) ,
223+ }
224+ }
225+ }
226+ }
227+ match ( internal_key, unspendable_key) {
228+ ( Some ( ref key) , _) => Ok ( ( key. clone ( ) , self . translate_unsatisfiable_pk ( & key) ) ) ,
229+ ( _, Some ( key) ) => Ok ( ( key, self ) ) ,
230+ _ => Err ( errstr ( "No viable internal key found." ) ) ,
231+ }
232+ }
233+
234+ /// Compile the [`Policy`] into a [`Tr`][`Descriptor::Tr`] Descriptor.
235+ ///
236+ /// ### TapTree compilation
237+ ///
238+ /// The policy tree constructed by root-level disjunctions over [`Or`][`Policy::Or`] and
239+ /// [`Thresh`][`Policy::Threshold`](1, ..) which is flattened into a vector (with respective
240+ /// probabilities derived from odds) of policies.
241+ /// For example, the policy `thresh(1,or(pk(A),pk(B)),and(or(pk(C),pk(D)),pk(E)))` gives the vector
242+ /// `[pk(A),pk(B),and(or(pk(C),pk(D)),pk(E)))]`. Each policy in the vector is compiled into
243+ /// the respective miniscripts. A Huffman Tree is created from this vector which optimizes over
244+ /// the probabilitity of satisfaction for the respective branch in the TapTree.
245+ // TODO: We might require other compile errors for Taproot.
246+ #[ cfg( feature = "compiler" ) ]
247+ pub fn compile_tr ( & self , unspendable_key : Option < Pk > ) -> Result < Descriptor < Pk > , Error > {
248+ self . is_valid ( ) ?; // Check for validity
249+ match self . is_safe_nonmalleable ( ) {
250+ ( false , _) => Err ( Error :: from ( CompilerError :: TopLevelNonSafe ) ) ,
251+ ( _, false ) => Err ( Error :: from (
252+ CompilerError :: ImpossibleNonMalleableCompilation ,
253+ ) ) ,
254+ _ => {
255+ let ( internal_key, policy) = self . clone ( ) . extract_key ( unspendable_key) ?;
256+ let tree = Descriptor :: new_tr (
257+ internal_key,
258+ match policy {
259+ Policy :: Trivial => None ,
260+ policy => Some ( policy. compile_tr_policy ( ) ?) ,
261+ } ,
262+ ) ?;
263+ Ok ( tree)
264+ }
265+ }
266+ }
267+
131268 /// Compile the descriptor into an optimized `Miniscript` representation
132269 #[ cfg( feature = "compiler" ) ]
133270 pub fn compile < Ctx : ScriptContext > ( & self ) -> Result < Miniscript < Pk , Ctx > , CompilerError > {
@@ -226,6 +363,30 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
226363 }
227364 }
228365
366+ /// Translate `Concrete::Key(key)` to `Concrete::Unsatisfiable` when extracting TapKey
367+ pub fn translate_unsatisfiable_pk ( self , key : & Pk ) -> Policy < Pk > {
368+ match self {
369+ Policy :: Key ( ref k) if k. clone ( ) == * key => Policy :: Unsatisfiable ,
370+ Policy :: And ( subs) => Policy :: And (
371+ subs. into_iter ( )
372+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
373+ . collect :: < Vec < _ > > ( ) ,
374+ ) ,
375+ Policy :: Or ( subs) => Policy :: Or (
376+ subs. into_iter ( )
377+ . map ( |( k, sub) | ( k, sub. translate_unsatisfiable_pk ( key) ) )
378+ . collect :: < Vec < _ > > ( ) ,
379+ ) ,
380+ Policy :: Threshold ( k, subs) => Policy :: Threshold (
381+ k,
382+ subs. into_iter ( )
383+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
384+ . collect :: < Vec < _ > > ( ) ,
385+ ) ,
386+ x => x,
387+ }
388+ }
389+
229390 /// Get all keys in the policy
230391 pub fn keys ( & self ) -> Vec < & Pk > {
231392 match * self {
@@ -645,3 +806,34 @@ where
645806 Policy :: from_tree_prob ( top, false ) . map ( |( _, result) | result)
646807 }
647808}
809+
810+ /// Create a Huffman Tree from compiled [Miniscript] nodes
811+ #[ cfg( feature = "compiler" ) ]
812+ fn with_huffman_tree < Pk : MiniscriptKey > (
813+ ms : Vec < ( OrdF64 , Miniscript < Pk , Tap > ) > ,
814+ ) -> Result < TapTree < Pk > , Error > {
815+ let mut node_weights = BinaryHeap :: < ( Reverse < OrdF64 > , TapTree < Pk > ) > :: new ( ) ;
816+ for ( prob, script) in ms {
817+ node_weights. push ( ( Reverse ( prob) , TapTree :: Leaf ( Arc :: new ( script) ) ) ) ;
818+ }
819+ if node_weights. is_empty ( ) {
820+ return Err ( errstr ( "Empty Miniscript compilation" ) ) ;
821+ }
822+ while node_weights. len ( ) > 1 {
823+ let ( p1, s1) = node_weights. pop ( ) . expect ( "len must atleast be two" ) ;
824+ let ( p2, s2) = node_weights. pop ( ) . expect ( "len must atleast be two" ) ;
825+
826+ let p = ( p1. 0 ) . 0 + ( p2. 0 ) . 0 ;
827+ node_weights. push ( (
828+ Reverse ( OrdF64 ( p) ) ,
829+ TapTree :: Tree ( Arc :: from ( s1) , Arc :: from ( s2) ) ,
830+ ) ) ;
831+ }
832+
833+ debug_assert ! ( node_weights. len( ) == 1 ) ;
834+ let node = node_weights
835+ . pop ( )
836+ . expect ( "huffman tree algorithm is broken" )
837+ . 1 ;
838+ Ok ( node)
839+ }
0 commit comments