2626use std:: { collections:: HashMap , sync:: Arc } ;
2727use std:: {
2828 fmt,
29- marker:: PhantomData ,
3029 str:: { self , FromStr } ,
3130} ;
3231
33- use bitcoin:: blockdata:: { opcodes, script} ;
3432use bitcoin:: secp256k1;
3533use bitcoin:: util:: bip32;
3634use bitcoin:: { self , Script } ;
3735
3836use self :: checksum:: verify_checksum;
39- use errstr;
4037use expression;
4138use miniscript;
42- use miniscript:: context:: { ScriptContext , ScriptContextError } ;
43- use miniscript:: { decode:: Terminal , Legacy , Miniscript , Segwitv0 } ;
44- use policy;
45- use push_opcode_size;
46- use script_num_size;
47- use util:: witness_to_scriptsig;
39+ use miniscript:: { Legacy , Miniscript , Segwitv0 } ;
4840use BareCtx ;
4941use Error ;
5042use MiniscriptKey ;
@@ -54,14 +46,15 @@ use ToPublicKey;
5446mod bare;
5547mod segwitv0;
5648mod sh;
49+ mod sortedmulti;
5750// Descriptor Exports
5851pub use self :: bare:: { Bare , Pkh } ;
5952pub use self :: segwitv0:: { Wpkh , Wsh } ;
6053pub use self :: sh:: Sh ;
54+ pub use self :: sortedmulti:: SortedMultiVec ;
6155
6256mod checksum;
6357mod key;
64- use self :: checksum:: desc_checksum;
6558pub use self :: key:: {
6659 DescriptorKeyParseError , DescriptorPublicKey , DescriptorPublicKeyCtx , DescriptorSecretKey ,
6760 DescriptorSinglePriv , DescriptorSinglePub , DescriptorXKey ,
@@ -677,225 +670,13 @@ impl<Pk: MiniscriptKey> fmt::Display for Descriptor<Pk> {
677670 }
678671}
679672
680- /// Contents of a "sortedmulti" descriptor
681- #[ derive( Clone , PartialEq , Eq , PartialOrd , Ord ) ]
682- pub struct SortedMultiVec < Pk : MiniscriptKey , Ctx : ScriptContext > {
683- /// signatures required
684- pub k : usize ,
685- /// public keys inside sorted Multi
686- pub pks : Vec < Pk > ,
687- /// The current ScriptContext for sortedmulti
688- pub ( crate ) phantom : PhantomData < Ctx > ,
689- }
690-
691- impl < Pk : MiniscriptKey , Ctx : ScriptContext > SortedMultiVec < Pk , Ctx > {
692- /// Create a new instance of `SortedMultiVec` given a list of keys and the threshold
693- ///
694- /// Internally checks all the applicable size limits and pubkey types limitations according to the current `Ctx`.
695- pub fn new ( k : usize , pks : Vec < Pk > ) -> Result < Self , Error > {
696- // A sortedmulti() is only defined for <= 20 keys (it maps to CHECKMULTISIG)
697- if pks. len ( ) > 20 {
698- Error :: BadDescriptor ( "Too many public keys" . to_string ( ) ) ;
699- }
700-
701- // Check the limits before creating a new SortedMultiVec
702- // For example, under p2sh context the scriptlen can only be
703- // upto 520 bytes.
704- let term: miniscript:: decode:: Terminal < Pk , Ctx > = Terminal :: Multi ( k, pks. clone ( ) ) ;
705- let ms = Miniscript :: from_ast ( term) ?;
706-
707- // This would check all the consensus rules for p2sh/p2wsh and
708- // even tapscript in future
709- Ctx :: check_local_validity ( & ms) ?;
710-
711- Ok ( Self {
712- k,
713- pks,
714- phantom : PhantomData ,
715- } )
716- }
717- /// Parse an expression tree into a SortedMultiVec
718- fn from_tree ( tree : & expression:: Tree ) -> Result < Self , Error >
719- where
720- <Pk as FromStr >:: Err : ToString ,
721- {
722- if tree. args . is_empty ( ) {
723- return Err ( errstr ( "no arguments given for sortedmulti" ) ) ;
724- }
725- let k = expression:: parse_num ( tree. args [ 0 ] . name ) ?;
726- if k > ( tree. args . len ( ) - 1 ) as u32 {
727- return Err ( errstr (
728- "higher threshold than there were keys in sortedmulti" ,
729- ) ) ;
730- }
731- let pks: Result < Vec < Pk > , _ > = tree. args [ 1 ..]
732- . iter ( )
733- . map ( |sub| expression:: terminal ( sub, Pk :: from_str) )
734- . collect ( ) ;
735-
736- pks. map ( |pks| SortedMultiVec :: new ( k as usize , pks) ) ?
737- }
738- }
739-
740- impl < Pk : MiniscriptKey , Ctx : ScriptContext > SortedMultiVec < Pk , Ctx > {
741- /// This will panic if translatefpk returns an uncompressed key when
742- /// converting to a Segwit descriptor. To prevent this panic, ensure
743- /// translatefpk returns an error in this case instead.
744- pub fn translate_pk < FPk , Q , FuncError > (
745- & self ,
746- translatefpk : & mut FPk ,
747- ) -> Result < SortedMultiVec < Q , Ctx > , FuncError >
748- where
749- FPk : FnMut ( & Pk ) -> Result < Q , FuncError > ,
750- Q : MiniscriptKey ,
751- {
752- let pks: Result < Vec < Q > , _ > = self . pks . iter ( ) . map ( & mut * translatefpk) . collect ( ) ;
753- Ok ( SortedMultiVec {
754- k : self . k ,
755- pks : pks?,
756- phantom : PhantomData ,
757- } )
758- }
759- }
760- impl < Pk : MiniscriptKey , Ctx : ScriptContext > SortedMultiVec < Pk , Ctx > {
761- // utility function to sanity a sorted multi vec
762- fn sanity_check ( & self ) -> Result < ( ) , Error > {
763- let ms: Miniscript < Pk , Ctx > =
764- Miniscript :: from_ast ( Terminal :: Multi ( self . k , self . pks . clone ( ) ) )
765- . expect ( "Must typecheck" ) ;
766- // '?' for doing From conversion
767- ms. sanity_check ( ) ?;
768- Ok ( ( ) )
769- }
770- }
771-
772- impl < Pk : MiniscriptKey , Ctx : ScriptContext > SortedMultiVec < Pk , Ctx > {
773- /// Create Terminal::Multi containing sorted pubkeys
774- pub fn sorted_node < ToPkCtx : Copy > ( & self , to_pk_ctx : ToPkCtx ) -> Terminal < Pk , Ctx >
775- where
776- Pk : ToPublicKey < ToPkCtx > ,
777- {
778- let mut pks = self . pks . clone ( ) ;
779- // Sort pubkeys lexicographically according to BIP 67
780- pks. sort_by ( |a, b| {
781- a. to_public_key ( to_pk_ctx)
782- . key
783- . serialize ( )
784- . partial_cmp ( & b. to_public_key ( to_pk_ctx) . key . serialize ( ) )
785- . unwrap ( )
786- } ) ;
787- Terminal :: Multi ( self . k , pks)
788- }
789-
790- /// Encode as a Bitcoin script
791- pub fn encode < ToPkCtx : Copy > ( & self , to_pk_ctx : ToPkCtx ) -> script:: Script
792- where
793- Pk : ToPublicKey < ToPkCtx > ,
794- {
795- self . sorted_node ( to_pk_ctx)
796- . encode ( script:: Builder :: new ( ) , to_pk_ctx)
797- . into_script ( )
798- }
799-
800- /// Attempt to produce a satisfying witness for the
801- /// witness script represented by the parse tree
802- pub fn satisfy < ToPkCtx , S > (
803- & self ,
804- satisfier : S ,
805- to_pk_ctx : ToPkCtx ,
806- ) -> Result < Vec < Vec < u8 > > , Error >
807- where
808- ToPkCtx : Copy ,
809- Pk : ToPublicKey < ToPkCtx > ,
810- S : Satisfier < ToPkCtx , Pk > ,
811- {
812- let ms = Miniscript :: from_ast ( self . sorted_node ( to_pk_ctx) ) . expect ( "Multi node typecheck" ) ;
813- ms. satisfy ( satisfier, to_pk_ctx)
814- }
815-
816- /// Size, in bytes of the script-pubkey. If this Miniscript is used outside
817- /// of segwit (e.g. in a bare or P2SH descriptor), this quantity should be
818- /// multiplied by 4 to compute the weight.
819- ///
820- /// In general, it is not recommended to use this function directly, but
821- /// to instead call the corresponding function on a `Descriptor`, which
822- /// will handle the segwit/non-segwit technicalities for you.
823- pub fn script_size ( & self ) -> usize {
824- script_num_size ( self . k )
825- + 1
826- + script_num_size ( self . pks . len ( ) )
827- + self . pks . iter ( ) . map ( |pk| pk. serialized_len ( ) ) . sum :: < usize > ( )
828- }
829-
830- /// Maximum number of witness elements used to satisfy the Miniscript
831- /// fragment, including the witness script itself. Used to estimate
832- /// the weight of the `VarInt` that specifies this number in a serialized
833- /// transaction.
834- ///
835- /// This function may panic on malformed `Miniscript` objects which do
836- /// not correspond to semantically sane Scripts. (Such scripts should be
837- /// rejected at parse time. Any exceptions are bugs.)
838- pub fn max_satisfaction_witness_elements ( & self ) -> usize {
839- 2 + self . k
840- }
841-
842- /// Maximum size, in bytes, of a satisfying witness. For Segwit outputs
843- /// `one_cost` should be set to 2, since the number `1` requires two
844- /// bytes to encode. For non-segwit outputs `one_cost` should be set to
845- /// 1, since `OP_1` is available in scriptSigs.
846- ///
847- /// In general, it is not recommended to use this function directly, but
848- /// to instead call the corresponding function on a `Descriptor`, which
849- /// will handle the segwit/non-segwit technicalities for you.
850- ///
851- /// All signatures are assumed to be 73 bytes in size, including the
852- /// length prefix (segwit) or push opcode (pre-segwit) and sighash
853- /// postfix.
854- ///
855- /// This function may panic on malformed `Miniscript` objects which do not
856- /// correspond to semantically sane Scripts. (Such scripts should be
857- /// rejected at parse time. Any exceptions are bugs.)
858- pub fn max_satisfaction_size ( & self , _: usize ) -> usize {
859- 1 + 73 * self . k
860- }
861- }
862-
863- impl < Pk : MiniscriptKey , Ctx : ScriptContext > policy:: Liftable < Pk > for SortedMultiVec < Pk , Ctx > {
864- fn lift ( & self ) -> Result < policy:: semantic:: Policy < Pk > , Error > {
865- let ret = policy:: semantic:: Policy :: Threshold (
866- self . k ,
867- self . pks
868- . clone ( )
869- . into_iter ( )
870- . map ( |k| policy:: semantic:: Policy :: KeyHash ( k. to_pubkeyhash ( ) ) )
871- . collect ( ) ,
872- ) ;
873- Ok ( ret)
874- }
875- }
876-
877- impl < Pk : MiniscriptKey , Ctx : ScriptContext > fmt:: Debug for SortedMultiVec < Pk , Ctx > {
878- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
879- fmt:: Display :: fmt ( self , f)
880- }
881- }
882-
883- impl < Pk : MiniscriptKey , Ctx : ScriptContext > fmt:: Display for SortedMultiVec < Pk , Ctx > {
884- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
885- write ! ( f, "sortedmulti({}" , self . k) ?;
886- for k in & self . pks {
887- write ! ( f, ",{}" , k) ?;
888- }
889- f. write_str ( ")" )
890- }
891- }
892-
893673serde_string_impl_pk ! ( Descriptor , "a script descriptor" ) ;
894674
895675#[ cfg( test) ]
896676mod tests {
677+ use super :: checksum:: desc_checksum;
678+ use super :: DescriptorPublicKeyCtx ;
897679 use super :: DescriptorTrait ;
898- use super :: { desc_checksum, DescriptorPublicKeyCtx } ;
899680 use bitcoin:: blockdata:: opcodes:: all:: { OP_CLTV , OP_CSV } ;
900681 use bitcoin:: blockdata:: script:: Instruction ;
901682 use bitcoin:: blockdata:: { opcodes, script} ;
0 commit comments