Skip to content

Commit 9a16e0e

Browse files
committed
Replace _assign with _tweak
The key methods `add_assign`, `add_expr_assign`, and `mul_assign` are cumbersome to use because a local variable that uses these methods changes meaning but keeps the same identifier. It would be more useful if we had methods that consumed `self` and returned a new key. Observe also that these to methods are for adding/multiplying a key by a tweak, rename the methods appropriately. Add methods `add_tweak` and `mul_tweak` to the `SecretKey` and `PublicKey` type. Deprecate `add_assign`, `add_expr_assign`, and `mul_assign`.
1 parent 4f7f138 commit 9a16e0e

File tree

2 files changed

+129
-48
lines changed

2 files changed

+129
-48
lines changed

src/key.rs

+128-47
Original file line numberDiff line numberDiff line change
@@ -227,55 +227,75 @@ impl SecretKey {
227227
}
228228
}
229229

230-
#[inline]
231230
/// Adds one secret key to another, modulo the curve order.
232231
///
233232
/// # Errors
234233
///
235234
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
236235
/// length slice.
237-
pub fn add_assign(
238-
&mut self,
239-
other: &[u8],
240-
) -> Result<(), Error> {
241-
if other.len() != 32 {
236+
#[inline]
237+
#[deprecated(since = "0.23.0", note = "Use add_tweak instead")]
238+
pub fn add_assign(&mut self, other: &[u8]) -> Result<(), Error> {
239+
*self = self.add_tweak(other)?;
240+
Ok(())
241+
}
242+
243+
/// Tweaks a [`SecretKey`] by adding `tweak` modulo the curve order.
244+
///
245+
/// # Errors
246+
///
247+
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
248+
/// length slice.
249+
#[inline]
250+
pub fn add_tweak(mut self, tweak: &[u8]) -> Result<SecretKey, Error> {
251+
if tweak.len() != 32 {
242252
return Err(Error::InvalidTweak);
243253
}
244254
unsafe {
245255
if ffi::secp256k1_ec_seckey_tweak_add(
246256
ffi::secp256k1_context_no_precomp,
247257
self.as_mut_c_ptr(),
248-
other.as_c_ptr(),
258+
tweak.as_c_ptr(),
249259
) != 1
250260
{
251261
Err(Error::InvalidTweak)
252262
} else {
253-
Ok(())
263+
Ok(self)
254264
}
255265
}
256266
}
257267

258-
#[inline]
259268
/// Multiplies one secret key by another, modulo the curve order. Will
260269
/// return an error if the resulting key would be invalid or if
261270
/// the tweak was not a 32-byte length slice.
262-
pub fn mul_assign(
263-
&mut self,
264-
other: &[u8],
265-
) -> Result<(), Error> {
266-
if other.len() != 32 {
271+
#[inline]
272+
#[deprecated(since = "0.23.0", note = "Use mul_tweak instead")]
273+
pub fn mul_assign(&mut self, other: &[u8]) -> Result<(), Error> {
274+
*self = self.mul_tweak(other)?;
275+
Ok(())
276+
}
277+
278+
/// Tweaks a [`SecretKey`] by multiplying by `tweak` modulo the curve order.
279+
///
280+
/// # Errors
281+
///
282+
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
283+
/// length slice.
284+
#[inline]
285+
pub fn mul_tweak(mut self, tweak: &[u8]) -> Result<SecretKey, Error> {
286+
if tweak.len() != 32 {
267287
return Err(Error::InvalidTweak);
268288
}
269289
unsafe {
270290
if ffi::secp256k1_ec_seckey_tweak_mul(
271291
ffi::secp256k1_context_no_precomp,
272292
self.as_mut_c_ptr(),
273-
other.as_c_ptr(),
293+
tweak.as_c_ptr(),
274294
) != 1
275295
{
276296
Err(Error::InvalidTweak)
277297
} else {
278-
Ok(())
298+
Ok(self)
279299
}
280300
}
281301
}
@@ -497,48 +517,82 @@ impl PublicKey {
497517
}
498518
}
499519

500-
#[inline]
501520
/// Adds the `other` public key to `self` in place.
502521
///
503522
/// # Errors
504523
///
505524
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
506525
/// length slice.
526+
#[inline]
527+
#[deprecated(since = "0.23.0", note = "Use add_tweak instead")]
507528
pub fn add_exp_assign<C: Verification>(
508529
&mut self,
509530
secp: &Secp256k1<C>,
510531
other: &[u8]
511532
) -> Result<(), Error> {
512-
if other.len() != 32 {
533+
*self = self.add_tweak(secp, other)?;
534+
Ok(())
535+
}
536+
537+
/// Tweaks a [`PublicKey`] by adding `tweak` modulo the curve order.
538+
///
539+
/// # Errors
540+
///
541+
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
542+
/// length slice.
543+
#[inline]
544+
pub fn add_tweak<C: Verification>(
545+
mut self,
546+
secp: &Secp256k1<C>,
547+
tweak: &[u8]
548+
) -> Result<PublicKey, Error> {
549+
if tweak.len() != 32 {
513550
return Err(Error::InvalidTweak);
514551
}
515552
unsafe {
516-
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
517-
Ok(())
553+
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, tweak.as_c_ptr()) == 1 {
554+
Ok(self)
518555
} else {
519556
Err(Error::InvalidTweak)
520557
}
521558
}
522559
}
523560

524-
#[inline]
525561
/// Muliplies the public key in place by the scalar `other`.
526562
///
527563
/// # Errors
528564
///
529565
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
530566
/// length slice.
567+
#[deprecated(since = "0.23.0", note = "Use mul_tweak instead")]
568+
#[inline]
531569
pub fn mul_assign<C: Verification>(
532570
&mut self,
533571
secp: &Secp256k1<C>,
534572
other: &[u8],
535573
) -> Result<(), Error> {
574+
*self = self.mul_tweak(secp, other)?;
575+
Ok(())
576+
}
577+
578+
/// Tweaks a [`PublicKey`] by multiplying by `tweak` modulo the curve order.
579+
///
580+
/// # Errors
581+
///
582+
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
583+
/// length slice.
584+
#[inline]
585+
pub fn mul_tweak<C: Verification>(
586+
mut self,
587+
secp: &Secp256k1<C>,
588+
other: &[u8],
589+
) -> Result<PublicKey, Error> {
536590
if other.len() != 32 {
537591
return Err(Error::InvalidTweak);
538592
}
539593
unsafe {
540594
if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
541-
Ok(())
595+
Ok(self)
542596
} else {
543597
Err(Error::InvalidTweak)
544598
}
@@ -1501,6 +1555,8 @@ pub mod serde_keypair {
15011555
#[cfg(test)]
15021556
#[allow(unused_imports)]
15031557
mod test {
1558+
use super::*;
1559+
15041560
use core::str::FromStr;
15051561

15061562
#[cfg(any(feature = "alloc", feature = "std"))]
@@ -1765,43 +1821,68 @@ mod test {
17651821

17661822
#[test]
17671823
#[cfg(any(feature = "alloc", feature = "std"))]
1768-
fn test_addition() {
1824+
fn tweak_add_arbitrary_data() {
17691825
let s = Secp256k1::new();
17701826

1771-
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
1772-
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
1827+
let (sk, pk) = s.generate_keypair(&mut thread_rng());
1828+
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
17731829

1774-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1775-
assert!(sk1.add_assign(&sk2[..]).is_ok());
1776-
assert!(pk1.add_exp_assign(&s, &sk2[..]).is_ok());
1777-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1830+
// TODO: This would be better tested with a _lot_ of different tweaks.
1831+
let tweak = random_32_bytes(&mut thread_rng());
17781832

1779-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1780-
assert!(sk2.add_assign(&sk1[..]).is_ok());
1781-
assert!(pk2.add_exp_assign(&s, &sk1[..]).is_ok());
1782-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1833+
let tweaked_sk = sk.add_tweak(&tweak[..]).unwrap();
1834+
assert_ne!(sk, tweaked_sk); // Make sure we did something.
1835+
let tweaked_pk = pk.add_tweak(&s, &tweak[..]).unwrap();
1836+
assert_ne!(pk, tweaked_pk);
1837+
1838+
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
17831839
}
17841840

17851841
#[test]
17861842
#[cfg(any(feature = "alloc", feature = "std"))]
1787-
fn test_multiplication() {
1843+
fn tweak_add_zero() {
1844+
let s = Secp256k1::new();
1845+
1846+
let (sk, pk) = s.generate_keypair(&mut thread_rng());
1847+
1848+
let tweak = &[0u8; 32];
1849+
1850+
let tweaked_sk = sk.add_tweak(tweak).unwrap();
1851+
assert_eq!(sk, tweaked_sk); // Tweak by zero does nothing.
1852+
let tweaked_pk = pk.add_tweak(&s, tweak).unwrap();
1853+
assert_eq!(pk, tweaked_pk);
1854+
}
1855+
1856+
#[test]
1857+
#[cfg(any(feature = "alloc", feature = "std"))]
1858+
fn tweak_mul_arbitrary_data() {
17881859
let s = Secp256k1::new();
17891860

1790-
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
1791-
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
1861+
let (sk, pk) = s.generate_keypair(&mut thread_rng());
1862+
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
17921863

1793-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1794-
assert!(sk1.mul_assign(&sk2[..]).is_ok());
1795-
assert!(pk1.mul_assign(&s, &sk2[..]).is_ok());
1796-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1864+
// TODO: This would be better tested with a _lot_ of different tweaks.
1865+
let tweak = random_32_bytes(&mut thread_rng());
17971866

1798-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1799-
assert!(sk2.mul_assign(&sk1[..]).is_ok());
1800-
assert!(pk2.mul_assign(&s, &sk1[..]).is_ok());
1801-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1867+
let tweaked_sk = sk.mul_tweak(&tweak[..]).unwrap();
1868+
assert_ne!(sk, tweaked_sk); // Make sure we did something.
1869+
let tweaked_pk = pk.mul_tweak(&s, &tweak[..]).unwrap();
1870+
assert_ne!(pk, tweaked_pk);
1871+
1872+
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
18021873
}
18031874

18041875
#[test]
1876+
#[cfg(any(feature = "alloc", feature = "std"))]
1877+
fn tweak_mul_zero() {
1878+
let s = Secp256k1::new();
1879+
let (sk, _) = s.generate_keypair(&mut thread_rng());
1880+
1881+
let tweak = &[0u8; 32];
1882+
assert!(sk.mul_tweak(tweak).is_err())
1883+
}
1884+
1885+
#[test]
18051886
#[cfg(any(feature = "alloc", feature = "std"))]
18061887
fn test_negation() {
18071888
let s = Secp256k1::new();
@@ -1904,7 +1985,7 @@ mod test {
19041985
fn create_pubkey_combine() {
19051986
let s = Secp256k1::new();
19061987

1907-
let (mut sk1, pk1) = s.generate_keypair(&mut thread_rng());
1988+
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
19081989
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());
19091990

19101991
let sum1 = pk1.combine(&pk2);
@@ -1913,8 +1994,8 @@ mod test {
19131994
assert!(sum2.is_ok());
19141995
assert_eq!(sum1, sum2);
19151996

1916-
assert!(sk1.add_assign(&sk2.as_ref()[..]).is_ok());
1917-
let sksum = PublicKey::from_secret_key(&s, &sk1);
1997+
let tweaked = sk1.add_tweak(&sk2.as_ref()[..]).unwrap();
1998+
let sksum = PublicKey::from_secret_key(&s, &tweaked);
19181999
assert_eq!(Ok(sksum), sum1);
19192000
}
19202001

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ pub enum Error {
337337
InvalidSharedSecret,
338338
/// Bad recovery id.
339339
InvalidRecoveryId,
340-
/// Invalid tweak for `add_*_assign` or `mul_*_assign`.
340+
/// Tried to add/multiply by an invalid tweak.
341341
InvalidTweak,
342342
/// Didn't pass enough memory to context creation with preallocated memory.
343343
NotEnoughMemory,

0 commit comments

Comments
 (0)