@@ -169,7 +169,7 @@ impl KeyPair {
169
169
/// Will return an error if the resulting key would be invalid or if
170
170
/// the tweak was not a 32-byte length slice.
171
171
#[ inline]
172
- pub fn add_assign < C : Verification > (
172
+ pub fn tweak_add_assign < C : Verification > (
173
173
& mut self ,
174
174
secp : & Secp256k1 < C > ,
175
175
tweak : & [ u8 ] ,
@@ -264,14 +264,17 @@ impl PublicKey {
264
264
ret
265
265
}
266
266
267
- /// Tweak a schnorrsig PublicKey by adding the generator multiplied with the given tweak to it.
268
- /// Will return an error if the resulting key would be invalid or if
269
- /// the tweak was not a 32-byte length slice.
270
- pub fn add_assign < V : Verification > (
267
+ /// Tweak an x-only PublicKey by adding the generator multiplied with the given tweak to it.
268
+ ///
269
+ /// Returns a boolean representing the parity of the tweaked key, which can be provided to
270
+ /// `tweak_add_check` which can be used to verify a tweak more efficiently than regenerating
271
+ /// it and checking equality. Will return an error if the resulting key would be invalid or
272
+ /// if the tweak was not a 32-byte length slice.
273
+ pub fn tweak_add_assign < V : Verification > (
271
274
& mut self ,
272
275
secp : & Secp256k1 < V > ,
273
276
tweak : & [ u8 ] ,
274
- ) -> Result < ( ) , Error > {
277
+ ) -> Result < bool , Error > {
275
278
if tweak. len ( ) != 32 {
276
279
return Err ( Error :: InvalidTweak ) ;
277
280
}
@@ -289,18 +292,57 @@ impl PublicKey {
289
292
return Err ( Error :: InvalidTweak ) ;
290
293
}
291
294
295
+ let mut parity: :: secp256k1_sys:: types:: c_int = 0 ;
292
296
err = ffi:: secp256k1_xonly_pubkey_from_pubkey (
293
297
secp. ctx ,
294
298
& mut self . 0 as * mut _ ,
295
- ptr :: null_mut ( ) ,
299
+ & mut parity as * mut _ ,
296
300
& pubkey,
297
301
) ;
298
302
299
- return if err == 0 {
303
+ if err == 0 {
300
304
Err ( Error :: InvalidPublicKey )
301
305
} else {
306
+ Ok ( parity != 0 )
307
+ }
308
+ }
309
+ }
310
+
311
+ /// Verify that a tweak produced by `tweak_add_assign` was computed correctly
312
+ ///
313
+ /// Should be called on the original untweaked key. Takes the tweaked key and
314
+ /// output parity from `tweak_add_assign` as input.
315
+ ///
316
+ /// Currently this is not much more efficient than just recomputing the tweak
317
+ /// and checking equality. However, in future this API will support batch
318
+ /// verification, which is significantly faster, so it is wise to design
319
+ /// protocols with this in mind.
320
+ pub fn tweak_add_check < V : Verification > (
321
+ & self ,
322
+ secp : & Secp256k1 < V > ,
323
+ tweaked_key : & Self ,
324
+ tweaked_parity : bool ,
325
+ tweak : & [ u8 ] ,
326
+ ) -> Result < ( ) , Error > {
327
+ if tweak. len ( ) != 32 {
328
+ return Err ( Error :: InvalidTweak ) ;
329
+ }
330
+
331
+ let tweaked_ser = tweaked_key. serialize ( ) ;
332
+ unsafe {
333
+ let err = ffi:: secp256k1_xonly_pubkey_tweak_add_check (
334
+ secp. ctx ,
335
+ tweaked_ser. as_c_ptr ( ) ,
336
+ if tweaked_parity { 1 } else { 0 } ,
337
+ & self . 0 as * const _ ,
338
+ tweak. as_c_ptr ( ) ,
339
+ ) ;
340
+
341
+ if err == 1 {
302
342
Ok ( ( ) )
303
- } ;
343
+ } else {
344
+ Err ( Error :: TweakCheckFailed )
345
+ }
304
346
}
305
347
}
306
348
}
@@ -720,9 +762,11 @@ mod tests {
720
762
let mut tweak = [ 0u8 ; 32 ] ;
721
763
thread_rng ( ) . fill_bytes ( & mut tweak) ;
722
764
let ( mut kp, mut pk) = s. generate_schnorrsig_keypair ( & mut thread_rng ( ) ) ;
723
- kp. add_assign ( & s, & tweak) . expect ( "Tweak error" ) ;
724
- pk. add_assign ( & s, & tweak) . expect ( "Tweak error" ) ;
765
+ let orig_pk = pk;
766
+ kp. tweak_add_assign ( & s, & tweak) . expect ( "Tweak error" ) ;
767
+ let parity = pk. tweak_add_assign ( & s, & tweak) . expect ( "Tweak error" ) ;
725
768
assert_eq ! ( PublicKey :: from_keypair( & s, & kp) , pk) ;
769
+ orig_pk. tweak_add_check ( & s, & pk, parity, & tweak) . expect ( "tweak check" ) ;
726
770
}
727
771
}
728
772
0 commit comments