@@ -83,6 +83,10 @@ impl KeyCtx {
8383 self . peers_key_share . as_ref ( ) . ok_or ( MultisigErrorKind :: MissingKeyShare )
8484 }
8585
86+ pub fn aggregated_key ( & self ) -> Result < & KeyPair > {
87+ self . aggregated_key . as_ref ( ) . ok_or ( MultisigErrorKind :: MissingAggPubKey )
88+ }
89+
8690 fn key_shares ( & self ) -> Result < [ & KeyPair ; 2 ] > {
8791 let mut shares = [ self . my_key_share ( ) ?, self . peers_key_share ( ) ?] ;
8892 shares. sort_by_key ( |p| p. pub_key ( ) ) ;
@@ -91,7 +95,7 @@ impl KeyCtx {
9195
9296 pub fn aggregate_pub_key_shares ( & mut self ) -> Result < ( ) > {
9397 let agg_ctx = KeyAggContext :: new ( self . key_shares ( ) ?. map ( |p| * p. pub_key ( ) ) ) ?;
94- self . aggregated_key = Some ( KeyPair :: from_public ( agg_ctx. aggregated_pubkey ( ) ) ) ;
98+ self . aggregated_key . get_or_insert ( KeyPair :: from_public ( agg_ctx. aggregated_pubkey ( ) ) ) ;
9599 self . key_agg_ctx = Some ( agg_ctx) ;
96100 Ok ( ( ) )
97101 }
@@ -138,13 +142,17 @@ pub struct TweakedKeyCtx {
138142}
139143
140144impl TweakedKeyCtx {
141- pub fn p2tr_address ( & self , network : Network ) -> Address {
145+ pub fn tweaked_public_key ( & self ) -> TweakedPublicKey {
142146 let pub_key: Point = self . key_agg_ctx . aggregated_pubkey ( ) ;
143147 let pub_key = pub_key. to_public_key ( ) . into ( ) ;
144148
145149 // This is safe, as `self` can only be constructed with a Taproot tweak applied to its
146150 // inner KeyAggContext (performed via the 'musig2::secp' crate):
147- Address :: p2tr_tweaked ( TweakedPublicKey :: dangerous_assume_tweaked ( pub_key) , network)
151+ TweakedPublicKey :: dangerous_assume_tweaked ( pub_key)
152+ }
153+
154+ pub fn p2tr_address ( & self , network : Network ) -> Address {
155+ Address :: p2tr_tweaked ( self . tweaked_public_key ( ) , network)
148156 }
149157}
150158
@@ -174,6 +182,10 @@ impl SigCtx {
174182 Ok ( & self . my_nonce_pair_share . as_ref ( ) . ok_or ( MultisigErrorKind :: MissingNonceShare ) ?. pub_nonce )
175183 }
176184
185+ fn peers_nonce_share ( & self ) -> Result < & PubNonce > {
186+ self . peers_nonce_share . as_ref ( ) . ok_or ( MultisigErrorKind :: MissingNonceShare )
187+ }
188+
177189 pub fn set_peers_nonce_share ( & mut self , nonce_share : PubNonce ) {
178190 self . peers_nonce_share . get_or_insert ( nonce_share) ;
179191 }
@@ -182,12 +194,19 @@ impl SigCtx {
182194 self . my_partial_sig . as_ref ( ) . ok_or ( MultisigErrorKind :: MissingPartialSig )
183195 }
184196
197+ fn peers_partial_sig ( & self ) -> Result < & PartialSignature > {
198+ self . peers_partial_sig . as_ref ( ) . ok_or ( MultisigErrorKind :: MissingPartialSig )
199+ }
200+
185201 pub fn set_peers_partial_sig ( & mut self , partial_signature : PartialSignature ) -> & PartialSignature {
186202 self . peers_partial_sig . get_or_insert ( partial_signature)
187203 }
188204
189205 pub fn set_adaptor_point ( & mut self , adaptor_point : Point ) -> Result < & Point > {
190- if self . my_partial_sig . is_none ( ) {
206+ // In order to have a better chance of provable security, don't allow the adaptor point to
207+ // be set after our local nonce share has already been initialized, as otherwise an attacker
208+ // may gain too much control over the challenge hash or final adapted signature nonce:
209+ if self . my_nonce_pair_share . is_none ( ) {
191210 self . adaptor_point = adaptor_point. into ( ) ;
192211 }
193212 match self . adaptor_point {
@@ -208,21 +227,8 @@ impl SigCtx {
208227 Ok ( ( ) )
209228 }
210229
211- fn get_nonce_shares ( & self ) -> Option < [ & PubNonce ; 2 ] > {
212- Some ( [ & self . my_nonce_pair_share . as_ref ( ) ?. pub_nonce , self . peers_nonce_share . as_ref ( ) ?] )
213- }
214-
215230 pub fn aggregate_nonce_shares ( & mut self ) -> Result < & AggNonce > {
216- let agg_nonce = AggNonce :: sum ( self . get_nonce_shares ( )
217- . ok_or ( MultisigErrorKind :: MissingNonceShare ) ?) ;
218- if matches ! ( ( & agg_nonce. R1 , & agg_nonce. R2 ) , ( MaybePoint :: Infinity , MaybePoint :: Infinity ) ) {
219- // Fail early if the aggregated nonce is zero, since otherwise an attacker could force
220- // the final signature nonce to be equal to the base point, G. While that might not be
221- // a problem (for us), there would be an attack vector if such signatures were ever
222- // deemed to be nonstandard. (Note that being able to assign blame later by allowing
223- // this through is unimportant for a two-party protocol.)
224- return Err ( MultisigErrorKind :: ZeroNonce ) ;
225- }
231+ let agg_nonce = AggNonce :: sum ( [ self . my_nonce_share ( ) ?, self . peers_nonce_share ( ) ?] ) ;
226232 Ok ( self . aggregated_nonce . insert ( agg_nonce) )
227233 }
228234
@@ -246,16 +252,11 @@ impl SigCtx {
246252 Ok ( self . my_partial_sig . insert ( sig) )
247253 }
248254
249- fn get_partial_signatures ( & self ) -> Option < [ PartialSignature ; 2 ] > {
250- Some ( [ self . my_partial_sig ?, self . peers_partial_sig ?] )
251- }
252-
253255 pub fn aggregate_partial_signatures ( & mut self ) -> Result < & AdaptorSignature > {
254256 let key_agg_ctx = & self . tweaked_key_ctx ( ) ?. key_agg_ctx ;
255257 let aggregated_nonce = & self . aggregated_nonce . as_ref ( )
256258 . ok_or ( MultisigErrorKind :: MissingAggNonce ) ?;
257- let partial_signatures = self . get_partial_signatures ( )
258- . ok_or ( MultisigErrorKind :: MissingPartialSig ) ?;
259+ let partial_signatures = [ * self . my_partial_sig ( ) ?, * self . peers_partial_sig ( ) ?] ;
259260 let message = self . message . as_ref ( )
260261 . ok_or ( MultisigErrorKind :: MissingPartialSig ) ?;
261262
@@ -267,6 +268,9 @@ impl SigCtx {
267268 pub fn compute_taproot_signature ( & self , adaptor_secret : MaybeScalar ) -> Result < Signature > {
268269 let adaptor_sig = self . aggregated_sig
269270 . ok_or ( MultisigErrorKind :: MissingAggSig ) ?;
271+ if self . adaptor_point != adaptor_secret. base_point_mul ( ) {
272+ return Err ( MultisigErrorKind :: MismatchedKeyPair ) ;
273+ }
270274 let sig_bytes: [ u8 ; 64 ] = adaptor_sig. adapt ( adaptor_secret)
271275 . ok_or ( MultisigErrorKind :: ZeroNonce ) ?;
272276 Ok ( Signature :: from_slice ( & sig_bytes) . expect ( "len = 64" ) )
@@ -288,7 +292,7 @@ pub trait PointExt {
288292impl PointExt for Point {
289293 fn to_public_key ( & self ) -> PublicKey {
290294 // NOTE: We have to round-trip the public key because 'musig2' & 'bitcoin' currently use
291- // different versions of the 'secp256k1' crate:
295+ // different versions of the 'secp256k1' crate. TODO: Consider unifying the versions.
292296 PublicKey :: from_slice ( & self . serialize_uncompressed ( ) )
293297 . expect ( "curve point should have a valid uncompressed DER encoding" )
294298 }
0 commit comments