Skip to content

Commit b9d08db

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`, `add_expr_tweak`, and `mul_tweak` to the `SecretKey` and `PublicKey` type. Deprecate `add_assign`, `add_expr_assign`, and `mul_assign`.
1 parent aab77b1 commit b9d08db

File tree

2 files changed

+125
-50
lines changed

2 files changed

+125
-50
lines changed

src/key.rs

+124-49
Original file line numberDiff line numberDiff line change
@@ -228,47 +228,67 @@ impl SecretKey {
228228
}
229229
}
230230

231-
#[inline]
232231
/// Adds one secret key to another, modulo the curve order.
233232
///
234233
/// # Errors
235234
///
236235
/// Returns an error if the resulting key would be invalid.
237-
pub fn add_assign(
238-
&mut self,
239-
other: &Scalar,
240-
) -> Result<(), Error> {
236+
#[inline]
237+
#[deprecated(since = "0.23.0", note = "Use add_tweak instead")]
238+
pub fn add_assign(&mut self, other: &Scalar) -> 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: &Scalar) -> Result<SecretKey, Error> {
241251
unsafe {
242252
if ffi::secp256k1_ec_seckey_tweak_add(
243253
ffi::secp256k1_context_no_precomp,
244254
self.as_mut_c_ptr(),
245-
other.as_c_ptr(),
255+
tweak.as_c_ptr(),
246256
) != 1
247257
{
248258
Err(Error::InvalidTweak)
249259
} else {
250-
Ok(())
260+
Ok(self)
251261
}
252262
}
253263
}
254264

255-
#[inline]
256265
/// Multiplies one secret key by another, modulo the curve order. Will
257266
/// return an error if the resulting key would be invalid.
258-
pub fn mul_assign(
259-
&mut self,
260-
other: &Scalar,
261-
) -> Result<(), Error> {
267+
#[inline]
268+
#[deprecated(since = "0.23.0", note = "Use mul_tweak instead")]
269+
pub fn mul_assign(&mut self, other: &Scalar) -> Result<(), Error> {
270+
*self = self.mul_tweak(other)?;
271+
Ok(())
272+
}
273+
274+
/// Tweaks a [`SecretKey`] by multiplying by `tweak` modulo the curve order.
275+
///
276+
/// # Errors
277+
///
278+
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
279+
/// length slice.
280+
#[inline]
281+
pub fn mul_tweak(mut self, tweak: &Scalar) -> Result<SecretKey, Error> {
262282
unsafe {
263283
if ffi::secp256k1_ec_seckey_tweak_mul(
264284
ffi::secp256k1_context_no_precomp,
265285
self.as_mut_c_ptr(),
266-
other.as_c_ptr(),
286+
tweak.as_c_ptr(),
267287
) != 1
268288
{
269289
Err(Error::InvalidTweak)
270290
} else {
271-
Ok(())
291+
Ok(self)
272292
}
273293
}
274294
}
@@ -490,40 +510,72 @@ impl PublicKey {
490510
}
491511
}
492512

493-
#[inline]
494513
/// Adds `other * G` to `self` in place.
495514
///
496515
/// # Errors
497516
///
498517
/// Returns an error if the resulting key would be invalid.
518+
#[inline]
519+
#[deprecated(since = "0.23.0", note = "Use add_exp_tweak instead")]
499520
pub fn add_exp_assign<C: Verification>(
500521
&mut self,
501522
secp: &Secp256k1<C>,
502523
other: &Scalar
503524
) -> Result<(), Error> {
525+
*self = self.add_exp_tweak(secp, other)?;
526+
Ok(())
527+
}
528+
529+
/// Tweaks a [`PublicKey`] by adding `tweak * G` modulo the curve order.
530+
///
531+
/// # Errors
532+
///
533+
/// Returns an error if the resulting key would be invalid.
534+
#[inline]
535+
pub fn add_exp_tweak<C: Verification>(
536+
mut self,
537+
secp: &Secp256k1<C>,
538+
tweak: &Scalar
539+
) -> Result<PublicKey, Error> {
504540
unsafe {
505-
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
506-
Ok(())
541+
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, tweak.as_c_ptr()) == 1 {
542+
Ok(self)
507543
} else {
508544
Err(Error::InvalidTweak)
509545
}
510546
}
511547
}
512548

513-
#[inline]
514549
/// Muliplies the public key in place by the scalar `other`.
515550
///
516551
/// # Errors
517552
///
518553
/// Returns an error if the resulting key would be invalid.
554+
#[deprecated(since = "0.23.0", note = "Use mul_tweak instead")]
555+
#[inline]
519556
pub fn mul_assign<C: Verification>(
520557
&mut self,
521558
secp: &Secp256k1<C>,
522559
other: &Scalar,
523560
) -> Result<(), Error> {
561+
*self = self.mul_tweak(secp, other)?;
562+
Ok(())
563+
}
564+
565+
/// Tweaks a [`PublicKey`] by multiplying by `tweak` modulo the curve order.
566+
///
567+
/// # Errors
568+
///
569+
/// Returns an error if the resulting key would be invalid.
570+
#[inline]
571+
pub fn mul_tweak<C: Verification>(
572+
mut self,
573+
secp: &Secp256k1<C>,
574+
other: &Scalar,
575+
) -> Result<PublicKey, Error> {
524576
unsafe {
525577
if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
526-
Ok(())
578+
Ok(self)
527579
} else {
528580
Err(Error::InvalidTweak)
529581
}
@@ -1474,6 +1526,8 @@ pub mod serde_keypair {
14741526
#[cfg(test)]
14751527
#[allow(unused_imports)]
14761528
mod test {
1529+
use super::*;
1530+
14771531
use core::str::FromStr;
14781532

14791533
#[cfg(any(feature = "alloc", feature = "std"))]
@@ -1738,48 +1792,69 @@ mod test {
17381792
}
17391793

17401794
#[test]
1741-
#[cfg(any(feature = "alloc", feature = "std"))]
1742-
fn test_addition() {
1795+
#[cfg(feature = "rand-std")]
1796+
fn tweak_add_arbitrary_data() {
17431797
let s = Secp256k1::new();
17441798

1745-
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
1746-
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
1747-
let scalar1 = Scalar::from(sk1);
1748-
let scalar2 = Scalar::from(sk1);
1799+
let (sk, pk) = s.generate_keypair(&mut thread_rng());
1800+
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
1801+
1802+
// TODO: This would be better tested with a _lot_ of different tweaks.
1803+
let tweak = Scalar::random();
17491804

1750-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1751-
assert!(sk1.add_assign(&scalar2).is_ok());
1752-
assert!(pk1.add_exp_assign(&s, &scalar2).is_ok());
1753-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1805+
let tweaked_sk = sk.add_tweak(&tweak).unwrap();
1806+
assert_ne!(sk, tweaked_sk); // Make sure we did something.
1807+
let tweaked_pk = pk.add_exp_tweak(&s, &tweak).unwrap();
1808+
assert_ne!(pk, tweaked_pk);
17541809

1755-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1756-
assert!(sk2.add_assign(&scalar1).is_ok());
1757-
assert!(pk2.add_exp_assign(&s, &scalar1).is_ok());
1758-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1810+
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
17591811
}
17601812

17611813
#[test]
17621814
#[cfg(any(feature = "alloc", feature = "std"))]
1763-
fn test_multiplication() {
1815+
fn tweak_add_zero() {
17641816
let s = Secp256k1::new();
17651817

1766-
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
1767-
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
1768-
let scalar1 = Scalar::from(sk1);
1769-
let scalar2 = Scalar::from(sk1);
1818+
let (sk, pk) = s.generate_keypair(&mut thread_rng());
17701819

1771-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1772-
assert!(sk1.mul_assign(&scalar2).is_ok());
1773-
assert!(pk1.mul_assign(&s, &scalar2).is_ok());
1774-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1820+
let tweak = Scalar::ZERO;
17751821

1776-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1777-
assert!(sk2.mul_assign(&scalar1).is_ok());
1778-
assert!(pk2.mul_assign(&s, &scalar1).is_ok());
1779-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1822+
let tweaked_sk = sk.add_tweak(&tweak).unwrap();
1823+
assert_eq!(sk, tweaked_sk); // Tweak by zero does nothing.
1824+
let tweaked_pk = pk.add_exp_tweak(&s, &tweak).unwrap();
1825+
assert_eq!(pk, tweaked_pk);
17801826
}
17811827

17821828
#[test]
1829+
#[cfg(feature = "rand-std")]
1830+
fn tweak_mul_arbitrary_data() {
1831+
let s = Secp256k1::new();
1832+
1833+
let (sk, pk) = s.generate_keypair(&mut thread_rng());
1834+
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
1835+
1836+
// TODO: This would be better tested with a _lot_ of different tweaks.
1837+
let tweak = Scalar::random();
1838+
1839+
let tweaked_sk = sk.mul_tweak(&tweak).unwrap();
1840+
assert_ne!(sk, tweaked_sk); // Make sure we did something.
1841+
let tweaked_pk = pk.mul_tweak(&s, &tweak).unwrap();
1842+
assert_ne!(pk, tweaked_pk);
1843+
1844+
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
1845+
}
1846+
1847+
#[test]
1848+
#[cfg(any(feature = "alloc", feature = "std"))]
1849+
fn tweak_mul_zero() {
1850+
let s = Secp256k1::new();
1851+
let (sk, _) = s.generate_keypair(&mut thread_rng());
1852+
1853+
let tweak = Scalar::ZERO;
1854+
assert!(sk.mul_tweak(&tweak).is_err())
1855+
}
1856+
1857+
#[test]
17831858
#[cfg(any(feature = "alloc", feature = "std"))]
17841859
fn test_negation() {
17851860
let s = Secp256k1::new();
@@ -1882,7 +1957,7 @@ mod test {
18821957
fn create_pubkey_combine() {
18831958
let s = Secp256k1::new();
18841959

1885-
let (mut sk1, pk1) = s.generate_keypair(&mut thread_rng());
1960+
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
18861961
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());
18871962

18881963
let sum1 = pk1.combine(&pk2);
@@ -1891,8 +1966,8 @@ mod test {
18911966
assert!(sum2.is_ok());
18921967
assert_eq!(sum1, sum2);
18931968

1894-
assert!(sk1.add_assign(&Scalar::from(sk2)).is_ok());
1895-
let sksum = PublicKey::from_secret_key(&s, &sk1);
1969+
let tweaked = sk1.add_tweak(&Scalar::from(sk2)).unwrap();
1970+
let sksum = PublicKey::from_secret_key(&s, &tweaked);
18961971
assert_eq!(Ok(sksum), sum1);
18971972
}
18981973

src/lib.rs

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

0 commit comments

Comments
 (0)