Skip to content

Commit 21604a7

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 e4fb575 commit 21604a7

File tree

2 files changed

+127
-48
lines changed

2 files changed

+127
-48
lines changed

src/key.rs

Lines changed: 126 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -232,55 +232,75 @@ impl SecretKey {
232232
}
233233
}
234234

235-
#[inline]
236235
/// Adds one secret key to another, modulo the curve order.
237236
///
238237
/// # Errors
239238
///
240239
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
241240
/// length slice.
242-
pub fn add_assign(
243-
&mut self,
244-
other: &[u8],
245-
) -> Result<(), Error> {
246-
if other.len() != 32 {
241+
#[inline]
242+
#[deprecated(since = "TODO: Set this prior to release", note = "Use add_tweak instead")]
243+
pub fn add_assign(&mut self, other: &[u8]) -> Result<(), Error> {
244+
*self = self.add_tweak(other)?;
245+
Ok(())
246+
}
247+
248+
/// Tweaks a [`SecretKey`] by adding `tweak` modulo the curve order.
249+
///
250+
/// # Errors
251+
///
252+
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
253+
/// length slice.
254+
#[inline]
255+
pub fn add_tweak(mut self, tweak: &[u8]) -> Result<SecretKey, Error> {
256+
if tweak.len() != 32 {
247257
return Err(Error::InvalidTweak);
248258
}
249259
unsafe {
250260
if ffi::secp256k1_ec_seckey_tweak_add(
251261
ffi::secp256k1_context_no_precomp,
252262
self.as_mut_c_ptr(),
253-
other.as_c_ptr(),
263+
tweak.as_c_ptr(),
254264
) != 1
255265
{
256266
Err(Error::InvalidTweak)
257267
} else {
258-
Ok(())
268+
Ok(self)
259269
}
260270
}
261271
}
262272

263-
#[inline]
264273
/// Multiplies one secret key by another, modulo the curve order. Will
265274
/// return an error if the resulting key would be invalid or if
266275
/// the tweak was not a 32-byte length slice.
267-
pub fn mul_assign(
268-
&mut self,
269-
other: &[u8],
270-
) -> Result<(), Error> {
271-
if other.len() != 32 {
276+
#[inline]
277+
#[deprecated(since = "TODO: Set this prior to release", note = "Use mul_tweak instead")]
278+
pub fn mul_assign(&mut self, other: &[u8]) -> Result<(), Error> {
279+
*self = self.mul_tweak(other)?;
280+
Ok(())
281+
}
282+
283+
/// Tweaks a [`SecretKey`] by multiplying by `tweak` modulo the curve order.
284+
///
285+
/// # Errors
286+
///
287+
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
288+
/// length slice.
289+
#[inline]
290+
pub fn mul_tweak(mut self, tweak: &[u8]) -> Result<SecretKey, Error> {
291+
if tweak.len() != 32 {
272292
return Err(Error::InvalidTweak);
273293
}
274294
unsafe {
275295
if ffi::secp256k1_ec_seckey_tweak_mul(
276296
ffi::secp256k1_context_no_precomp,
277297
self.as_mut_c_ptr(),
278-
other.as_c_ptr(),
298+
tweak.as_c_ptr(),
279299
) != 1
280300
{
281301
Err(Error::InvalidTweak)
282302
} else {
283-
Ok(())
303+
Ok(self)
284304
}
285305
}
286306
}
@@ -470,48 +490,82 @@ impl PublicKey {
470490
}
471491
}
472492

473-
#[inline]
474493
/// Adds the `other` public key to `self` in place.
475494
///
476495
/// # Errors
477496
///
478497
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
479498
/// length slice.
499+
#[inline]
500+
#[deprecated(since = "TODO: Set this prior to release", note = "Use add_tweak instead")]
480501
pub fn add_exp_assign<C: Verification>(
481502
&mut self,
482503
secp: &Secp256k1<C>,
483504
other: &[u8]
484505
) -> Result<(), Error> {
485-
if other.len() != 32 {
506+
*self = self.add_tweak(secp, other)?;
507+
Ok(())
508+
}
509+
510+
/// Tweaks a [`PublicKey`] by adding `tweak` modulo the curve order.
511+
///
512+
/// # Errors
513+
///
514+
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
515+
/// length slice.
516+
#[inline]
517+
pub fn add_tweak<C: Verification>(
518+
mut self,
519+
secp: &Secp256k1<C>,
520+
tweak: &[u8]
521+
) -> Result<PublicKey, Error> {
522+
if tweak.len() != 32 {
486523
return Err(Error::InvalidTweak);
487524
}
488525
unsafe {
489-
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
490-
Ok(())
526+
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, tweak.as_c_ptr()) == 1 {
527+
Ok(self)
491528
} else {
492529
Err(Error::InvalidTweak)
493530
}
494531
}
495532
}
496533

497-
#[inline]
498534
/// Muliplies the public key in place by the scalar `other`.
499535
///
500536
/// # Errors
501537
///
502538
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
503539
/// length slice.
540+
#[deprecated(since = "TODO: Set this prior to release", note = "Use mul_tweak instead")]
541+
#[inline]
504542
pub fn mul_assign<C: Verification>(
505543
&mut self,
506544
secp: &Secp256k1<C>,
507545
other: &[u8],
508546
) -> Result<(), Error> {
547+
*self = self.mul_tweak(secp, other)?;
548+
Ok(())
549+
}
550+
551+
/// Tweaks a [`PublicKey`] by multiplying by `tweak` modulo the curve order.
552+
///
553+
/// # Errors
554+
///
555+
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
556+
/// length slice.
557+
#[inline]
558+
pub fn mul_tweak<C: Verification>(
559+
mut self,
560+
secp: &Secp256k1<C>,
561+
other: &[u8],
562+
) -> Result<PublicKey, Error> {
509563
if other.len() != 32 {
510564
return Err(Error::InvalidTweak);
511565
}
512566
unsafe {
513567
if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
514-
Ok(())
568+
Ok(self)
515569
} else {
516570
Err(Error::InvalidTweak)
517571
}
@@ -1740,43 +1794,68 @@ mod test {
17401794

17411795
#[test]
17421796
#[cfg(any(feature = "alloc", feature = "std"))]
1743-
fn test_addition() {
1797+
fn tweak_add_arbitrary_data() {
17441798
let s = Secp256k1::new();
17451799

1746-
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
1747-
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
1800+
let (sk, pk) = s.generate_keypair(&mut thread_rng());
1801+
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
17481802

1749-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1750-
assert!(sk1.add_assign(&sk2[..]).is_ok());
1751-
assert!(pk1.add_exp_assign(&s, &sk2[..]).is_ok());
1752-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1803+
// TODO: This would be better tested with a _lot_ of different tweaks.
1804+
let tweak = random_32_bytes(&mut thread_rng());
17531805

1754-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1755-
assert!(sk2.add_assign(&sk1[..]).is_ok());
1756-
assert!(pk2.add_exp_assign(&s, &sk1[..]).is_ok());
1757-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1806+
let tweaked_sk = sk.add_tweak(&tweak[..]).unwrap();
1807+
assert_ne!(sk, tweaked_sk); // Make sure we did something.
1808+
let tweaked_pk = pk.add_tweak(&s, &tweak[..]).unwrap();
1809+
assert_ne!(pk, tweaked_pk);
1810+
1811+
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
17581812
}
17591813

17601814
#[test]
17611815
#[cfg(any(feature = "alloc", feature = "std"))]
1762-
fn test_multiplication() {
1816+
fn tweak_add_zero() {
1817+
let s = Secp256k1::new();
1818+
1819+
let (sk, pk) = s.generate_keypair(&mut thread_rng());
1820+
1821+
let tweak = &[0u8; 32];
1822+
1823+
let tweaked_sk = sk.add_tweak(tweak).unwrap();
1824+
assert_eq!(sk, tweaked_sk); // Tweak by zero does nothing.
1825+
let tweaked_pk = pk.add_tweak(&s, tweak).unwrap();
1826+
assert_eq!(pk, tweaked_pk);
1827+
}
1828+
1829+
#[test]
1830+
#[cfg(any(feature = "alloc", feature = "std"))]
1831+
fn tweak_mul_arbitrary_data() {
17631832
let s = Secp256k1::new();
17641833

1765-
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
1766-
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
1834+
let (sk, pk) = s.generate_keypair(&mut thread_rng());
1835+
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
17671836

1768-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1769-
assert!(sk1.mul_assign(&sk2[..]).is_ok());
1770-
assert!(pk1.mul_assign(&s, &sk2[..]).is_ok());
1771-
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
1837+
// TODO: This would be better tested with a _lot_ of different tweaks.
1838+
let tweak = random_32_bytes(&mut thread_rng());
17721839

1773-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1774-
assert!(sk2.mul_assign(&sk1[..]).is_ok());
1775-
assert!(pk2.mul_assign(&s, &sk1[..]).is_ok());
1776-
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
1840+
let tweaked_sk = sk.mul_tweak(&tweak[..]).unwrap();
1841+
assert_ne!(sk, tweaked_sk); // Make sure we did something.
1842+
let tweaked_pk = pk.mul_tweak(&s, &tweak[..]).unwrap();
1843+
assert_ne!(pk, tweaked_pk);
1844+
1845+
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
17771846
}
17781847

17791848
#[test]
1849+
#[cfg(any(feature = "alloc", feature = "std"))]
1850+
fn tweak_mul_zero() {
1851+
let s = Secp256k1::new();
1852+
let (sk, _) = s.generate_keypair(&mut thread_rng());
1853+
1854+
let tweak = &[0u8; 32];
1855+
assert!(sk.mul_tweak(tweak).is_err())
1856+
}
1857+
1858+
#[test]
17801859
#[cfg(any(feature = "alloc", feature = "std"))]
17811860
fn test_negation() {
17821861
let s = Secp256k1::new();
@@ -1879,7 +1958,7 @@ mod test {
18791958
fn create_pubkey_combine() {
18801959
let s = Secp256k1::new();
18811960

1882-
let (mut sk1, pk1) = s.generate_keypair(&mut thread_rng());
1961+
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
18831962
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());
18841963

18851964
let sum1 = pk1.combine(&pk2);
@@ -1888,8 +1967,8 @@ mod test {
18881967
assert!(sum2.is_ok());
18891968
assert_eq!(sum1, sum2);
18901969

1891-
assert!(sk1.add_assign(&sk2.as_ref()[..]).is_ok());
1892-
let sksum = PublicKey::from_secret_key(&s, &sk1);
1970+
let tweaked = sk1.add_tweak(&sk2.as_ref()[..]).unwrap();
1971+
let sksum = PublicKey::from_secret_key(&s, &tweaked);
18931972
assert_eq!(Ok(sksum), sum1);
18941973
}
18951974

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ pub enum Error {
356356
InvalidSharedSecret,
357357
/// Bad recovery id.
358358
InvalidRecoveryId,
359-
/// Invalid tweak for `add_*_assign` or `mul_*_assign`.
359+
/// Tried to add/multiply by an invalid tweak.
360360
InvalidTweak,
361361
/// Didn't pass enough memory to context creation with preallocated memory.
362362
NotEnoughMemory,

0 commit comments

Comments
 (0)