@@ -417,6 +417,7 @@ where
417
417
}
418
418
}
419
419
420
+ #[ cfg( not( fuzzing) ) ]
420
421
impl < Pk , Ctx > expression:: FromTree for Terminal < Pk , Ctx >
421
422
where
422
423
Pk : MiniscriptKey + str:: FromStr ,
@@ -503,15 +504,7 @@ where
503
504
} ) ,
504
505
( "1" , 0 ) => Ok ( Terminal :: True ) ,
505
506
( "0" , 0 ) => Ok ( Terminal :: False ) ,
506
- ( "and_v" , 2 ) => {
507
- let expr = expression:: binary ( top, Terminal :: AndV ) ?;
508
- if let Terminal :: AndV ( _, ref right) = expr {
509
- if let Terminal :: True = right. node {
510
- return Err ( Error :: NonCanonicalTrue ) ;
511
- }
512
- }
513
- Ok ( expr)
514
- }
507
+ ( "and_v" , 2 ) => expression:: binary ( top, Terminal :: AndV ) ,
515
508
( "and_b" , 2 ) => expression:: binary ( top, Terminal :: AndB ) ,
516
509
( "and_n" , 2 ) => Ok ( Terminal :: AndOr (
517
510
expression:: FromTree :: from_tree ( & top. args [ 0 ] ) ?,
@@ -526,15 +519,7 @@ where
526
519
( "or_b" , 2 ) => expression:: binary ( top, Terminal :: OrB ) ,
527
520
( "or_d" , 2 ) => expression:: binary ( top, Terminal :: OrD ) ,
528
521
( "or_c" , 2 ) => expression:: binary ( top, Terminal :: OrC ) ,
529
- ( "or_i" , 2 ) => {
530
- let expr = expression:: binary ( top, Terminal :: OrI ) ?;
531
- if let Terminal :: OrI ( ref left, ref right) = expr {
532
- if left. node == Terminal :: False || right. node == Terminal :: False {
533
- return Err ( Error :: NonCanonicalFalse ) ;
534
- }
535
- }
536
- Ok ( expr)
537
- }
522
+ ( "or_i" , 2 ) => expression:: binary ( top, Terminal :: OrI ) ,
538
523
( "thresh" , n) => {
539
524
if n == 0 {
540
525
return Err ( errstr ( "no arguments given" ) ) ;
@@ -815,3 +800,206 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
815
800
}
816
801
}
817
802
}
803
+
804
+ #[ cfg( fuzzing) ]
805
+ impl < Pk , Ctx > expression:: FromTree for Terminal < Pk , Ctx >
806
+ where
807
+ Pk : MiniscriptKey + str:: FromStr ,
808
+ Pk :: Hash : str:: FromStr ,
809
+ Ctx : ScriptContext ,
810
+ <Pk as str:: FromStr >:: Err : ToString ,
811
+ <<Pk as MiniscriptKey >:: Hash as str:: FromStr >:: Err : ToString ,
812
+ {
813
+ fn from_tree ( top : & expression:: Tree ) -> Result < Terminal < Pk , Ctx > , Error > {
814
+ let mut aliased_wrap;
815
+ let frag_name;
816
+ let frag_wrap;
817
+ let mut name_split = top. name . split ( ':' ) ;
818
+ match ( name_split. next ( ) , name_split. next ( ) , name_split. next ( ) ) {
819
+ ( None , _, _) => {
820
+ frag_name = "" ;
821
+ frag_wrap = "" ;
822
+ }
823
+ ( Some ( name) , None , _) => {
824
+ if name == "pk" {
825
+ frag_name = "pk_k" ;
826
+ frag_wrap = "c" ;
827
+ } else if name == "pkh" {
828
+ frag_name = "pk_h" ;
829
+ frag_wrap = "c" ;
830
+ } else {
831
+ frag_name = name;
832
+ frag_wrap = "" ;
833
+ }
834
+ }
835
+ ( Some ( wrap) , Some ( name) , None ) => {
836
+ if wrap. is_empty ( ) {
837
+ return Err ( Error :: Unexpected ( top. name . to_owned ( ) ) ) ;
838
+ }
839
+ if name == "pk" {
840
+ frag_name = "pk_k" ;
841
+ aliased_wrap = wrap. to_owned ( ) ;
842
+ aliased_wrap. push_str ( "c" ) ;
843
+ frag_wrap = & aliased_wrap;
844
+ } else if name == "pkh" {
845
+ frag_name = "pk_h" ;
846
+ aliased_wrap = wrap. to_owned ( ) ;
847
+ aliased_wrap. push_str ( "c" ) ;
848
+ frag_wrap = & aliased_wrap;
849
+ } else {
850
+ frag_name = name;
851
+ frag_wrap = wrap;
852
+ }
853
+ }
854
+ ( Some ( _) , Some ( _) , Some ( _) ) => {
855
+ return Err ( Error :: MultiColon ( top. name . to_owned ( ) ) ) ;
856
+ }
857
+ }
858
+ let mut unwrapped = match ( frag_name, top. args . len ( ) ) {
859
+ ( "pk_k" , 1 ) => {
860
+ expression:: terminal ( & top. args [ 0 ] , |x| Pk :: from_str ( x) . map ( Terminal :: PkK ) )
861
+ }
862
+ ( "pk_h" , 1 ) => {
863
+ expression:: terminal ( & top. args [ 0 ] , |x| Pk :: Hash :: from_str ( x) . map ( Terminal :: PkH ) )
864
+ }
865
+ ( "after" , 1 ) => expression:: terminal ( & top. args [ 0 ] , |x| {
866
+ expression:: parse_num ( x) . map ( Terminal :: After )
867
+ } ) ,
868
+ ( "older" , 1 ) => expression:: terminal ( & top. args [ 0 ] , |x| {
869
+ expression:: parse_num ( x) . map ( Terminal :: Older )
870
+ } ) ,
871
+ ( "sha256" , 1 ) => expression:: terminal ( & top. args [ 0 ] , |x| {
872
+ sha256:: Hash :: from_hex ( x) . map ( Terminal :: Sha256 )
873
+ } ) ,
874
+ ( "hash256" , 1 ) => expression:: terminal ( & top. args [ 0 ] , |x| {
875
+ sha256d:: Hash :: from_hex ( x)
876
+ . map ( |x| x. into_inner ( ) )
877
+ . map ( |mut x| {
878
+ x. reverse ( ) ;
879
+ x
880
+ } )
881
+ . map ( |x| Terminal :: Hash256 ( sha256d:: Hash :: from_inner ( x) ) )
882
+ } ) ,
883
+ ( "ripemd160" , 1 ) => expression:: terminal ( & top. args [ 0 ] , |x| {
884
+ ripemd160:: Hash :: from_hex ( x) . map ( Terminal :: Ripemd160 )
885
+ } ) ,
886
+ ( "hash160" , 1 ) => expression:: terminal ( & top. args [ 0 ] , |x| {
887
+ hash160:: Hash :: from_hex ( x) . map ( Terminal :: Hash160 )
888
+ } ) ,
889
+ ( "1" , 0 ) => Ok ( Terminal :: True ) ,
890
+ ( "0" , 0 ) => Ok ( Terminal :: False ) ,
891
+ ( "and_v" , 2 ) => {
892
+ let expr = expression:: binary ( top, Terminal :: AndV ) ?;
893
+ if let Terminal :: AndV ( _, ref right) = expr {
894
+ if let Terminal :: True = right. node {
895
+ return Err ( Error :: Unexpected ( String :: from ( "NonCannonicalTrue" ) ) ) ;
896
+ }
897
+ }
898
+ Ok ( expr)
899
+ }
900
+ ( "and_b" , 2 ) => expression:: binary ( top, Terminal :: AndB ) ,
901
+ ( "and_n" , 2 ) => Ok ( Terminal :: AndOr (
902
+ expression:: FromTree :: from_tree ( & top. args [ 0 ] ) ?,
903
+ expression:: FromTree :: from_tree ( & top. args [ 1 ] ) ?,
904
+ Arc :: new ( Miniscript :: from_ast ( Terminal :: False ) ?) ,
905
+ ) ) ,
906
+ ( "andor" , 3 ) => Ok ( Terminal :: AndOr (
907
+ expression:: FromTree :: from_tree ( & top. args [ 0 ] ) ?,
908
+ expression:: FromTree :: from_tree ( & top. args [ 1 ] ) ?,
909
+ expression:: FromTree :: from_tree ( & top. args [ 2 ] ) ?,
910
+ ) ) ,
911
+ ( "or_b" , 2 ) => expression:: binary ( top, Terminal :: OrB ) ,
912
+ ( "or_d" , 2 ) => expression:: binary ( top, Terminal :: OrD ) ,
913
+ ( "or_c" , 2 ) => expression:: binary ( top, Terminal :: OrC ) ,
914
+ ( "or_i" , 2 ) => {
915
+ let expr = expression:: binary ( top, Terminal :: OrI ) ?;
916
+ if let Terminal :: OrI ( ref left, ref right) = expr {
917
+ if left. node == Terminal :: False || right. node == Terminal :: False {
918
+ return Err ( Error :: Unexpected ( String :: from ( "NonCannonicalFalse" ) ) ) ;
919
+ }
920
+ }
921
+ Ok ( expr)
922
+ }
923
+ ( "thresh" , n) => {
924
+ if n == 0 {
925
+ return Err ( errstr ( "no arguments given" ) ) ;
926
+ }
927
+ let k = expression:: terminal ( & top. args [ 0 ] , expression:: parse_num) ? as usize ;
928
+ if k > n - 1 {
929
+ return Err ( errstr ( "higher threshold than there are subexpressions" ) ) ;
930
+ }
931
+ if n == 1 {
932
+ return Err ( errstr ( "empty thresholds not allowed in descriptors" ) ) ;
933
+ }
934
+
935
+ let subs: Result < Vec < Arc < Miniscript < Pk , Ctx > > > , _ > = top. args [ 1 ..]
936
+ . iter ( )
937
+ . map ( |sub| expression:: FromTree :: from_tree ( sub) )
938
+ . collect ( ) ;
939
+
940
+ Ok ( Terminal :: Thresh ( k, subs?) )
941
+ }
942
+ ( "multi" , n) => {
943
+ if n == 0 {
944
+ return Err ( errstr ( "no arguments given" ) ) ;
945
+ }
946
+ let k = expression:: terminal ( & top. args [ 0 ] , expression:: parse_num) ? as usize ;
947
+ if k > n - 1 {
948
+ return Err ( errstr ( "higher threshold than there were keys in multi" ) ) ;
949
+ }
950
+
951
+ let pks: Result < Vec < Pk > , _ > = top. args [ 1 ..]
952
+ . iter ( )
953
+ . map ( |sub| expression:: terminal ( sub, Pk :: from_str) )
954
+ . collect ( ) ;
955
+
956
+ pks. map ( |pks| Terminal :: Multi ( k, pks) )
957
+ }
958
+ _ => Err ( Error :: Unexpected ( format ! (
959
+ "{}({} args) while parsing Miniscript" ,
960
+ top. name,
961
+ top. args. len( ) ,
962
+ ) ) ) ,
963
+ } ?;
964
+ for ch in frag_wrap. chars ( ) . rev ( ) {
965
+ // Check whether the wrapper is valid under the current context
966
+ let ms = Miniscript :: from_ast ( unwrapped) ?;
967
+ Ctx :: check_global_validity ( & ms) ?;
968
+ match ch {
969
+ 'a' => unwrapped = Terminal :: Alt ( Arc :: new ( ms) ) ,
970
+ 's' => unwrapped = Terminal :: Swap ( Arc :: new ( ms) ) ,
971
+ 'c' => unwrapped = Terminal :: Check ( Arc :: new ( ms) ) ,
972
+ 'd' => unwrapped = Terminal :: DupIf ( Arc :: new ( ms) ) ,
973
+ 'v' => unwrapped = Terminal :: Verify ( Arc :: new ( ms) ) ,
974
+ 'j' => unwrapped = Terminal :: NonZero ( Arc :: new ( ms) ) ,
975
+ 'n' => unwrapped = Terminal :: ZeroNotEqual ( Arc :: new ( ms) ) ,
976
+ 't' => {
977
+ unwrapped = Terminal :: AndV (
978
+ Arc :: new ( ms) ,
979
+ Arc :: new ( Miniscript :: from_ast ( Terminal :: True ) ?) ,
980
+ )
981
+ }
982
+ 'u' => {
983
+ unwrapped = Terminal :: OrI (
984
+ Arc :: new ( ms) ,
985
+ Arc :: new ( Miniscript :: from_ast ( Terminal :: False ) ?) ,
986
+ )
987
+ }
988
+ 'l' => {
989
+ if ms. node == Terminal :: False {
990
+ return Err ( Error :: LikelyFalse ) ;
991
+ }
992
+ unwrapped = Terminal :: OrI (
993
+ Arc :: new ( Miniscript :: from_ast ( Terminal :: False ) ?) ,
994
+ Arc :: new ( ms) ,
995
+ )
996
+ }
997
+ x => return Err ( Error :: UnknownWrapper ( x) ) ,
998
+ }
999
+ }
1000
+ // Check whether the unwrapped miniscript is valid under the current context
1001
+ let ms = Miniscript :: from_ast ( unwrapped) ?;
1002
+ Ctx :: check_global_validity ( & ms) ?;
1003
+ Ok ( ms. node )
1004
+ }
1005
+ }
0 commit comments