1919
2020use std:: fmt;
2121
22- use secp256k1_zkp:: Scalar ;
23- pub use secp256k1_zkp:: { XOnlyPublicKey , KeyPair } ;
24- use secp256k1_zkp:: { self , Secp256k1 , Verification , constants:: SCHNORR_SIGNATURE_SIZE } ;
25- use crate :: hashes:: { Hash , HashEngine } ;
2622use crate :: taproot:: { TapBranchHash , TapTweakHash } ;
2723use crate :: SchnorrSigHashType ;
24+ use secp256k1_zkp:: { self , constants:: SCHNORR_SIGNATURE_SIZE , Secp256k1 , Verification } ;
25+ pub use secp256k1_zkp:: { KeyPair , XOnlyPublicKey } ;
2826
2927/// Untweaked Schnorr public key
3028pub type UntweakedPublicKey = XOnlyPublicKey ;
@@ -33,38 +31,70 @@ pub type UntweakedPublicKey = XOnlyPublicKey;
3331#[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash , Debug ) ]
3432pub struct TweakedPublicKey ( XOnlyPublicKey ) ;
3533
36- /// A trait for tweaking Schnorr public keys
34+ /// Untweaked Schnorr key pair
35+ pub type UntweakedKeyPair = KeyPair ;
36+
37+ /// Tweaked Schnorr key pair
38+ #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Debug ) ]
39+ pub struct TweakedKeyPair ( KeyPair ) ;
40+
41+ /// A trait for tweaking Schnorr key types (x-only public keys and key pairs).
3742pub trait TapTweak {
38- /// Tweaks an untweaked public key given an untweaked key and optional script tree merkle root.
43+ /// Tweaked key type with optional auxiliary information
44+ type TweakedAux ;
45+ /// Tweaked key type
46+ type TweakedKey ;
47+
48+ /// Tweaks an untweaked key with corresponding public key value and optional script tree merkle
49+ /// root. For the [`KeyPair`] type this also tweaks the private key in the pair.
3950 ///
4051 /// This is done by using the equation Q = P + H(P|c)G, where
41- /// * Q is the tweaked key
42- /// * P is the internal key
52+ /// * Q is the tweaked public key
53+ /// * P is the internal public key
4354 /// * H is the hash function
4455 /// * c is the commitment data
4556 /// * G is the generator point
46- fn tap_tweak < C : Verification > ( self , secp : & Secp256k1 < C > , merkle_root : Option < TapBranchHash > ) -> ( TweakedPublicKey , secp256k1_zkp:: Parity ) ;
57+ ///
58+ /// # Returns
59+ /// The tweaked key and its parity.
60+ fn tap_tweak < C : Verification > (
61+ self ,
62+ secp : & Secp256k1 < C > ,
63+ merkle_root : Option < TapBranchHash > ,
64+ ) -> Self :: TweakedAux ;
4765
48- /// Directly convert an UntweakedPublicKey to a TweakedPublicKey
66+ /// Directly converts to a `TweakedKey`
4967 ///
5068 /// This method is dangerous and can lead to loss of funds if used incorrectly.
5169 /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
52- fn dangerous_assume_tweaked ( self ) -> TweakedPublicKey ;
70+ fn dangerous_assume_tweaked ( self ) -> Self :: TweakedKey ;
5371}
5472
5573impl TapTweak for UntweakedPublicKey {
56- fn tap_tweak < C : Verification > ( self , secp : & Secp256k1 < C > , merkle_root : Option < TapBranchHash > ) -> ( TweakedPublicKey , secp256k1_zkp:: Parity ) {
57- // Compute the tweak
58- let mut engine = TapTweakHash :: engine ( ) ;
59- engine. input ( & self . serialize ( ) ) ;
60- merkle_root. map ( |hash| engine. input ( & hash) ) ;
61- let tweak_value: [ u8 ; 32 ] = TapTweakHash :: from_engine ( engine) . into_inner ( ) ;
62- let tweak_value = Scalar :: from_be_bytes ( tweak_value) . expect ( "hash value greater than curve order" ) ;
63-
64- //Tweak the internal key by the tweak value
65- let ( output_key, parity) = self . clone ( ) . add_tweak ( secp, & tweak_value) . expect ( "Tap tweak failed" ) ;
66- debug_assert ! ( self . tweak_add_check( & secp, & output_key, parity, tweak_value) ) ;
74+ type TweakedAux = ( TweakedPublicKey , secp256k1_zkp:: Parity ) ;
75+ type TweakedKey = TweakedPublicKey ;
76+
77+ /// Tweaks an untweaked public key with corresponding public key value and optional script tree
78+ /// merkle root.
79+ ///
80+ /// This is done by using the equation Q = P + H(P|c)G, where
81+ /// * Q is the tweaked public key
82+ /// * P is the internal public key
83+ /// * H is the hash function
84+ /// * c is the commitment data
85+ /// * G is the generator point
86+ ///
87+ /// # Returns
88+ /// The tweaked key and its parity.
89+ fn tap_tweak < C : Verification > (
90+ self ,
91+ secp : & Secp256k1 < C > ,
92+ merkle_root : Option < TapBranchHash > ,
93+ ) -> ( TweakedPublicKey , secp256k1_zkp:: Parity ) {
94+ let tweak = TapTweakHash :: from_key_and_tweak ( self , merkle_root) . to_scalar ( ) ;
95+ let ( output_key, parity) = self . add_tweak ( secp, & tweak) . expect ( "Tap tweak failed" ) ;
6796
97+ debug_assert ! ( self . tweak_add_check( secp, & output_key, parity, tweak) ) ;
6898 ( TweakedPublicKey ( output_key) , parity)
6999 }
70100
@@ -74,8 +104,42 @@ impl TapTweak for UntweakedPublicKey {
74104 }
75105}
76106
107+ impl TapTweak for UntweakedKeyPair {
108+ type TweakedAux = TweakedKeyPair ;
109+ type TweakedKey = TweakedKeyPair ;
110+
111+ /// Tweaks private and public keys within an untweaked [`KeyPair`] with corresponding public key
112+ /// value and optional script tree merkle root.
113+ ///
114+ /// This is done by tweaking private key within the pair using the equation q = p + H(P|c), where
115+ /// * q is the tweaked private key
116+ /// * p is the internal private key
117+ /// * H is the hash function
118+ /// * c is the commitment data
119+ /// The public key is generated from a private key by multiplying with generator point, Q = qG.
120+ ///
121+ /// # Returns
122+ /// The tweaked key and its parity.
123+ fn tap_tweak < C : Verification > ( self , secp : & Secp256k1 < C > , merkle_root : Option < TapBranchHash > ) -> TweakedKeyPair {
124+ let ( pubkey, _parity) = XOnlyPublicKey :: from_keypair ( & self ) ;
125+ let tweak = TapTweakHash :: from_key_and_tweak ( pubkey, merkle_root) . to_scalar ( ) ;
126+ let tweaked = self . add_xonly_tweak ( secp, & tweak) . expect ( "Tap tweak failed" ) ;
127+ TweakedKeyPair ( tweaked)
128+ }
129+
130+ fn dangerous_assume_tweaked ( self ) -> TweakedKeyPair {
131+ TweakedKeyPair ( self )
132+ }
133+ }
77134
78135impl TweakedPublicKey {
136+ /// Returns the [`TweakedPublicKey`] for `keypair`.
137+ #[ inline]
138+ pub fn from_keypair ( keypair : TweakedKeyPair ) -> Self {
139+ let ( xonly, _parity) = keypair. 0 . x_only_public_key ( ) ;
140+ TweakedPublicKey ( xonly)
141+ }
142+
79143 /// Create a new [TweakedPublicKey] from a [PublicKey]. No tweak is applied.
80144 pub fn new ( key : XOnlyPublicKey ) -> TweakedPublicKey {
81145 TweakedPublicKey ( key)
@@ -92,6 +156,52 @@ impl TweakedPublicKey {
92156 }
93157}
94158
159+ impl TweakedKeyPair {
160+ /// Creates a new [`TweakedKeyPair`] from a [`KeyPair`]. No tweak is applied, consider
161+ /// calling `tap_tweak` on an [`UntweakedKeyPair`] instead of using this constructor.
162+ ///
163+ /// This method is dangerous and can lead to loss of funds if used incorrectly.
164+ /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
165+ #[ inline]
166+ pub fn dangerous_assume_tweaked ( pair : KeyPair ) -> TweakedKeyPair {
167+ TweakedKeyPair ( pair)
168+ }
169+
170+ /// Returns the underlying key pair.
171+ #[ inline]
172+ pub fn to_inner ( self ) -> KeyPair {
173+ self . 0
174+ }
175+
176+ /// Returns the [`TweakedPublicKey`] and its [`Parity`] for this [`TweakedKeyPair`].
177+ #[ inline]
178+ pub fn public_parts ( & self ) -> ( TweakedPublicKey , secp256k1_zkp:: Parity ) {
179+ let ( xonly, parity) = self . 0 . x_only_public_key ( ) ;
180+ ( TweakedPublicKey ( xonly) , parity)
181+ }
182+ }
183+
184+ impl From < TweakedPublicKey > for XOnlyPublicKey {
185+ #[ inline]
186+ fn from ( pair : TweakedPublicKey ) -> Self {
187+ pair. 0
188+ }
189+ }
190+
191+ impl From < TweakedKeyPair > for KeyPair {
192+ #[ inline]
193+ fn from ( pair : TweakedKeyPair ) -> Self {
194+ pair. 0
195+ }
196+ }
197+
198+ impl From < TweakedKeyPair > for TweakedPublicKey {
199+ #[ inline]
200+ fn from ( pair : TweakedKeyPair ) -> Self {
201+ TweakedPublicKey :: from_keypair ( pair)
202+ }
203+ }
204+
95205/// A BIP340-341 serialized schnorr signature with the corresponding hash type.
96206#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
97207#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) , serde( crate = "actual_serde" ) ) ]
0 commit comments