@@ -8,7 +8,7 @@ use Types::Common -sigs, -types;
8
8
9
9
use Bitcoin::Crypto::Types -types;
10
10
use Bitcoin::Crypto::Constants;
11
- use Bitcoin::Crypto::Util qw( get_key_type) ;
11
+ use Bitcoin::Crypto::Util qw( get_key_type tagged_hash ) ;
12
12
use Bitcoin::Crypto::Helpers qw( ensure_length ecc) ;
13
13
use Bitcoin::Crypto::Exception;
14
14
@@ -73,7 +73,7 @@ sub has_purpose
73
73
74
74
signature_for raw_key => (
75
75
method => Object,
76
- positional => [Maybe [Enum [qw( private public public_compressed) ]], {default => undef }],
76
+ positional => [Maybe [Enum [qw( private public public_compressed public_xonly ) ]], {default => undef }],
77
77
);
78
78
79
79
# helpers for raw_key
@@ -99,6 +99,7 @@ sub raw_key
99
99
{
100
100
my ($self , $type ) = @_ ;
101
101
my $is_private = $self -> _is_private;
102
+ my $key = $self -> key_instance;
102
103
103
104
$type //= $is_private ? ' private' : ' public' ;
104
105
if ($type eq ' public' && (!$self -> does(' Bitcoin::Crypto::Role::Compressed' ) || $self -> compressed)) {
@@ -110,17 +111,52 @@ sub raw_key
110
111
' cannot create private key from a public key'
111
112
) unless $is_private ;
112
113
113
- return $self -> __full_private($self -> key_instance);
114
+ return $self -> __full_private($key );
115
+ }
116
+ elsif ($type eq ' public_xonly' ) {
117
+ $key = $self -> __private_to_public($key )
118
+ if $is_private ;
119
+
120
+ return ecc-> xonly_public_key($self -> __public_compressed($key , 1));
114
121
}
115
122
else {
116
- my $key = $self -> key_instance;
117
123
$key = $self -> __private_to_public($key )
118
124
if $is_private ;
119
125
120
126
return $self -> __public_compressed($key , $type eq ' public_compressed' );
121
127
}
128
+ }
129
+
130
+ signature_for taproot_tweaked_key => (
131
+ method => Object,
132
+ head => [Maybe [Enum [qw( private public) ]], {default => undef }],
133
+ named => [
134
+ tweak_suffix => Maybe [ByteStr],
135
+ {default => undef },
136
+ ],
137
+ bless => !!0,
138
+ );
122
139
123
- # no need to check for invalid input, since we have a signature with enum
140
+ sub taproot_tweaked_key
141
+ {
142
+ my ($self , $type , $args ) = @_ ;
143
+ $type //= $self -> _is_private ? ' private' : ' public' ;
144
+
145
+ if ($type eq ' private' ) {
146
+ my $internal = $self -> raw_key(' private' );
147
+ my $internal_public = ecc-> create_public_key($internal );
148
+ $internal = ecc-> negate_private_key($internal )
149
+ if substr ($internal_public , 0, 1) eq " \x03 " ;
150
+
151
+ my $tweak = tagged_hash(ecc-> xonly_public_key($internal_public ) . ($args -> {tweak_suffix } // ' ' ), ' TapTweak' );
152
+ return ecc-> add_private_key($internal , $tweak );
153
+ }
154
+ else {
155
+ my $internal = $self -> raw_key(' public_xonly' );
156
+ my $tweak = tagged_hash($internal . ($args -> {tweak_suffix } // ' ' ), ' TapTweak' );
157
+ my $combined = ecc-> combine_public_keys(ecc-> create_public_key($tweak ), " \x02 " . $internal );
158
+ return ecc-> xonly_public_key($combined );
159
+ }
124
160
}
125
161
126
162
1;
0 commit comments