@@ -169,7 +169,7 @@ impl KeyPair {
169169 /// Will return an error if the resulting key would be invalid or if
170170 /// the tweak was not a 32-byte length slice.
171171 #[ inline]
172- pub fn add_assign < C : Verification > (
172+ pub fn tweak_add_assign < C : Verification > (
173173 & mut self ,
174174 secp : & Secp256k1 < C > ,
175175 tweak : & [ u8 ] ,
@@ -264,14 +264,17 @@ impl PublicKey {
264264 ret
265265 }
266266
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 > (
271274 & mut self ,
272275 secp : & Secp256k1 < V > ,
273276 tweak : & [ u8 ] ,
274- ) -> Result < ( ) , Error > {
277+ ) -> Result < bool , Error > {
275278 if tweak. len ( ) != 32 {
276279 return Err ( Error :: InvalidTweak ) ;
277280 }
@@ -289,18 +292,57 @@ impl PublicKey {
289292 return Err ( Error :: InvalidTweak ) ;
290293 }
291294
295+ let mut parity: :: secp256k1_sys:: types:: c_int = 0 ;
292296 err = ffi:: secp256k1_xonly_pubkey_from_pubkey (
293297 secp. ctx ,
294298 & mut self . 0 as * mut _ ,
295- ptr :: null_mut ( ) ,
299+ & mut parity as * mut _ ,
296300 & pubkey,
297301 ) ;
298302
299- return if err == 0 {
303+ if err == 0 {
300304 Err ( Error :: InvalidPublicKey )
301305 } 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 {
302342 Ok ( ( ) )
303- } ;
343+ } else {
344+ Err ( Error :: TweakCheckFailed )
345+ }
304346 }
305347 }
306348}
@@ -720,9 +762,11 @@ mod tests {
720762 let mut tweak = [ 0u8 ; 32 ] ;
721763 thread_rng ( ) . fill_bytes ( & mut tweak) ;
722764 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" ) ;
725768 assert_eq ! ( PublicKey :: from_keypair( & s, & kp) , pk) ;
769+ orig_pk. tweak_add_check ( & s, & pk, parity, & tweak) . expect ( "tweak check" ) ;
726770 }
727771 }
728772
0 commit comments