Merge rust-bitcoin/rust-secp256k1#435: Add functional style methods to various keys
12d4583638
Implement negate that consumes self (Tobin Harding)5eb2d745b7
Rename tweak_add_assign -> add_tweak (Tobin Harding)b9d08db8eb
Replace _assign with _tweak (Tobin Harding) Pull request description: The various `_assign` methods (`add_assign`, `add_expr_assign`, `mul_assign`, `tweak_add_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 the newly modified type. We notice also that this API is for adding/multiplying tweaks not arbitraryly adding keys. - Patch 1: Changes add/mul_assign -> add/mul_tweak for `PublicKey` and `SecretKey` (incl. re-working unit tests) - Patch 2: Changes `tweak_add_assign` -> `add_tweak` for `KeyPair` and `XOnlyPublicKey` - Patch 3: Changes `negate_assign` -> `negate` All methods changed include: - New method consumes self and returns the tweaked key - Original method remains with a `deprecated` attribute, however I've left a TODO in there for adding the `since` field. Close: #415 ACKs for top commit: apoelstra: ACK12d4583638
Tree-SHA512: 026e8722892f3a0f18956281e4d2356d2789ef535a7ab71a375758201b180663d068397cde2dca5f60858ab7158069e53d7096326bfbd5a364269b0be680940c
This commit is contained in:
commit
4dacf55ed5
303
src/key.rs
303
src/key.rs
|
@ -233,11 +233,16 @@ impl SecretKey {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Negates the secret key.
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Negates one secret key.
|
#[deprecated(since = "0.23.0", note = "Use negate instead")]
|
||||||
pub fn negate_assign(
|
pub fn negate_assign(&mut self) {
|
||||||
&mut self
|
*self = self.negate()
|
||||||
) {
|
}
|
||||||
|
|
||||||
|
/// Negates the secret key.
|
||||||
|
#[inline]
|
||||||
|
pub fn negate(mut self) -> SecretKey {
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = ffi::secp256k1_ec_seckey_negate(
|
let res = ffi::secp256k1_ec_seckey_negate(
|
||||||
ffi::secp256k1_context_no_precomp,
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
@ -245,49 +250,70 @@ impl SecretKey {
|
||||||
);
|
);
|
||||||
debug_assert_eq!(res, 1);
|
debug_assert_eq!(res, 1);
|
||||||
}
|
}
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Adds one secret key to another, modulo the curve order.
|
/// Adds one secret key to another, modulo the curve order.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the resulting key would be invalid.
|
/// Returns an error if the resulting key would be invalid.
|
||||||
pub fn add_assign(
|
#[inline]
|
||||||
&mut self,
|
#[deprecated(since = "0.23.0", note = "Use add_tweak instead")]
|
||||||
other: &Scalar,
|
pub fn add_assign(&mut self, other: &Scalar) -> Result<(), Error> {
|
||||||
) -> Result<(), Error> {
|
*self = self.add_tweak(other)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tweaks a [`SecretKey`] by adding `tweak` modulo the curve order.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
|
||||||
|
/// length slice.
|
||||||
|
#[inline]
|
||||||
|
pub fn add_tweak(mut self, tweak: &Scalar) -> Result<SecretKey, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_seckey_tweak_add(
|
if ffi::secp256k1_ec_seckey_tweak_add(
|
||||||
ffi::secp256k1_context_no_precomp,
|
ffi::secp256k1_context_no_precomp,
|
||||||
self.as_mut_c_ptr(),
|
self.as_mut_c_ptr(),
|
||||||
other.as_c_ptr(),
|
tweak.as_c_ptr(),
|
||||||
) != 1
|
) != 1
|
||||||
{
|
{
|
||||||
Err(Error::InvalidTweak)
|
Err(Error::InvalidTweak)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Multiplies one secret key by another, modulo the curve order. Will
|
/// Multiplies one secret key by another, modulo the curve order. Will
|
||||||
/// return an error if the resulting key would be invalid.
|
/// return an error if the resulting key would be invalid.
|
||||||
pub fn mul_assign(
|
#[inline]
|
||||||
&mut self,
|
#[deprecated(since = "0.23.0", note = "Use mul_tweak instead")]
|
||||||
other: &Scalar,
|
pub fn mul_assign(&mut self, other: &Scalar) -> Result<(), Error> {
|
||||||
) -> Result<(), Error> {
|
*self = self.mul_tweak(other)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tweaks a [`SecretKey`] by multiplying by `tweak` modulo the curve order.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
|
||||||
|
/// length slice.
|
||||||
|
#[inline]
|
||||||
|
pub fn mul_tweak(mut self, tweak: &Scalar) -> Result<SecretKey, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_seckey_tweak_mul(
|
if ffi::secp256k1_ec_seckey_tweak_mul(
|
||||||
ffi::secp256k1_context_no_precomp,
|
ffi::secp256k1_context_no_precomp,
|
||||||
self.as_mut_c_ptr(),
|
self.as_mut_c_ptr(),
|
||||||
other.as_c_ptr(),
|
tweak.as_c_ptr(),
|
||||||
) != 1
|
) != 1
|
||||||
{
|
{
|
||||||
Err(Error::InvalidTweak)
|
Err(Error::InvalidTweak)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -502,52 +528,89 @@ impl PublicKey {
|
||||||
debug_assert_eq!(ret_len, ret.len());
|
debug_assert_eq!(ret_len, ret.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Negates the public key in place.
|
/// Negates the public key in place.
|
||||||
pub fn negate_assign<C: Verification>(
|
#[inline]
|
||||||
&mut self,
|
#[deprecated(since = "0.23.0", note = "Use negate instead")]
|
||||||
secp: &Secp256k1<C>
|
pub fn negate_assign<C: Verification>(&mut self, secp: &Secp256k1<C>) {
|
||||||
) {
|
*self = self.negate(secp)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Negates the public key.
|
||||||
|
#[inline]
|
||||||
|
pub fn negate<C: Verification>(mut self, secp: &Secp256k1<C>) -> PublicKey {
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = ffi::secp256k1_ec_pubkey_negate(secp.ctx, &mut self.0);
|
let res = ffi::secp256k1_ec_pubkey_negate(secp.ctx, &mut self.0);
|
||||||
debug_assert_eq!(res, 1);
|
debug_assert_eq!(res, 1);
|
||||||
}
|
}
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Adds `other * G` to `self` in place.
|
/// Adds `other * G` to `self` in place.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the resulting key would be invalid.
|
/// Returns an error if the resulting key would be invalid.
|
||||||
|
#[inline]
|
||||||
|
#[deprecated(since = "0.23.0", note = "Use add_exp_tweak instead")]
|
||||||
pub fn add_exp_assign<C: Verification>(
|
pub fn add_exp_assign<C: Verification>(
|
||||||
&mut self,
|
&mut self,
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
other: &Scalar
|
other: &Scalar
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
*self = self.add_exp_tweak(secp, other)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tweaks a [`PublicKey`] by adding `tweak * G` modulo the curve order.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the resulting key would be invalid.
|
||||||
|
#[inline]
|
||||||
|
pub fn add_exp_tweak<C: Verification>(
|
||||||
|
mut self,
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
tweak: &Scalar
|
||||||
|
) -> Result<PublicKey, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
|
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, tweak.as_c_ptr()) == 1 {
|
||||||
Ok(())
|
Ok(self)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidTweak)
|
Err(Error::InvalidTweak)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Muliplies the public key in place by the scalar `other`.
|
/// Muliplies the public key in place by the scalar `other`.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the resulting key would be invalid.
|
/// Returns an error if the resulting key would be invalid.
|
||||||
|
#[deprecated(since = "0.23.0", note = "Use mul_tweak instead")]
|
||||||
|
#[inline]
|
||||||
pub fn mul_assign<C: Verification>(
|
pub fn mul_assign<C: Verification>(
|
||||||
&mut self,
|
&mut self,
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
other: &Scalar,
|
other: &Scalar,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
*self = self.mul_tweak(secp, other)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tweaks a [`PublicKey`] by multiplying by `tweak` modulo the curve order.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the resulting key would be invalid.
|
||||||
|
#[inline]
|
||||||
|
pub fn mul_tweak<C: Verification>(
|
||||||
|
mut self,
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
other: &Scalar,
|
||||||
|
) -> Result<PublicKey, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
|
if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
|
||||||
Ok(())
|
Ok(self)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidTweak)
|
Err(Error::InvalidTweak)
|
||||||
}
|
}
|
||||||
|
@ -868,6 +931,18 @@ impl KeyPair {
|
||||||
|
|
||||||
/// Tweaks a keypair by adding the given tweak to the secret key and updating the public key
|
/// Tweaks a keypair by adding the given tweak to the secret key and updating the public key
|
||||||
/// accordingly.
|
/// accordingly.
|
||||||
|
#[inline]
|
||||||
|
#[deprecated(since = "0.23.0", note = "Use add_xonly_tweak instead")]
|
||||||
|
pub fn tweak_add_assign<C: Verification>(
|
||||||
|
&mut self,
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
tweak: &Scalar,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
*self = self.add_xonly_tweak(secp, tweak)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tweaks a keypair by first converting the public key to an xonly key and tweaking it.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
|
@ -887,16 +962,16 @@ impl KeyPair {
|
||||||
/// let tweak = Scalar::random();
|
/// let tweak = Scalar::random();
|
||||||
///
|
///
|
||||||
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
|
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
|
||||||
/// key_pair.tweak_add_assign(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak");
|
/// let tweaked = key_pair.add_xonly_tweak(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak");
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
// TODO: Add checked implementation
|
// TODO: Add checked implementation
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn tweak_add_assign<C: Verification>(
|
pub fn add_xonly_tweak<C: Verification>(
|
||||||
&mut self,
|
mut self,
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
tweak: &Scalar,
|
tweak: &Scalar,
|
||||||
) -> Result<(), Error> {
|
) -> Result<KeyPair, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let err = ffi::secp256k1_keypair_xonly_tweak_add(
|
let err = ffi::secp256k1_keypair_xonly_tweak_add(
|
||||||
secp.ctx,
|
secp.ctx,
|
||||||
|
@ -907,7 +982,7 @@ impl KeyPair {
|
||||||
return Err(Error::InvalidTweak);
|
return Err(Error::InvalidTweak);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1153,12 +1228,24 @@ impl XOnlyPublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tweaks an x-only PublicKey by adding the generator multiplied with the given tweak to it.
|
/// Tweaks an x-only PublicKey by adding the generator multiplied with the given tweak to it.
|
||||||
|
#[deprecated(since = "0.23.0", note = "Use add_tweak instead")]
|
||||||
|
pub fn tweak_add_assign<V: Verification>(
|
||||||
|
&mut self,
|
||||||
|
secp: &Secp256k1<V>,
|
||||||
|
tweak: &Scalar,
|
||||||
|
) -> Result<Parity, Error> {
|
||||||
|
let (tweaked, parity) = self.add_tweak(secp, tweak)?;
|
||||||
|
*self = tweaked;
|
||||||
|
Ok(parity)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tweaks an [`XOnlyPublicKey`] by adding the generator multiplied with the given tweak to it.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// An opaque type representing the parity of the tweaked key, this should be provided to
|
/// The newly tweaked key plus an opaque type representing the parity of the tweaked key, this
|
||||||
/// `tweak_add_check` which can be used to verify a tweak more efficiently than regenerating
|
/// should be provided to `tweak_add_check` which can be used to verify a tweak more efficiently
|
||||||
/// it and checking equality.
|
/// than regenerating it and checking equality.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
|
@ -1168,22 +1255,22 @@ impl XOnlyPublicKey {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[cfg(all(feature = "std", feature = "rand-std"))] {
|
/// # #[cfg(all(feature = "std", feature = "rand-std"))] {
|
||||||
/// use secp256k1::{Secp256k1, KeyPair, Scalar};
|
/// use secp256k1::{Secp256k1, KeyPair, Scalar, XOnlyPublicKey};
|
||||||
/// use secp256k1::rand::{RngCore, thread_rng};
|
/// use secp256k1::rand::{RngCore, thread_rng};
|
||||||
///
|
///
|
||||||
/// let secp = Secp256k1::new();
|
/// let secp = Secp256k1::new();
|
||||||
/// let tweak = Scalar::random();
|
/// let tweak = Scalar::random();
|
||||||
///
|
///
|
||||||
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
|
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
|
||||||
/// let (mut public_key, _parity) = key_pair.x_only_public_key();
|
/// let (xonly, _parity) = key_pair.x_only_public_key();
|
||||||
/// public_key.tweak_add_assign(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak");
|
/// let tweaked = xonly.add_tweak(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak");
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn tweak_add_assign<V: Verification>(
|
pub fn add_tweak<V: Verification>(
|
||||||
&mut self,
|
mut self,
|
||||||
secp: &Secp256k1<V>,
|
secp: &Secp256k1<V>,
|
||||||
tweak: &Scalar,
|
tweak: &Scalar,
|
||||||
) -> Result<Parity, Error> {
|
) -> Result<(XOnlyPublicKey, Parity), Error> {
|
||||||
let mut pk_parity = 0;
|
let mut pk_parity = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut pubkey = ffi::PublicKey::new();
|
let mut pubkey = ffi::PublicKey::new();
|
||||||
|
@ -1207,7 +1294,8 @@ impl XOnlyPublicKey {
|
||||||
return Err(Error::InvalidPublicKey);
|
return Err(Error::InvalidPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parity::from_i32(pk_parity).map_err(Into::into)
|
let parity = Parity::from_i32(pk_parity)?;
|
||||||
|
Ok((self, parity))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1802,67 +1890,88 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(feature = "rand-std")]
|
||||||
fn test_addition() {
|
fn tweak_add_arbitrary_data() {
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
|
|
||||||
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
|
let (sk, pk) = s.generate_keypair(&mut thread_rng());
|
||||||
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
|
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
|
||||||
let scalar1 = Scalar::from(sk1);
|
|
||||||
let scalar2 = Scalar::from(sk1);
|
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
// TODO: This would be better tested with a _lot_ of different tweaks.
|
||||||
assert!(sk1.add_assign(&scalar2).is_ok());
|
let tweak = Scalar::random();
|
||||||
assert!(pk1.add_exp_assign(&s, &scalar2).is_ok());
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
let tweaked_sk = sk.add_tweak(&tweak).unwrap();
|
||||||
assert!(sk2.add_assign(&scalar1).is_ok());
|
assert_ne!(sk, tweaked_sk); // Make sure we did something.
|
||||||
assert!(pk2.add_exp_assign(&s, &scalar1).is_ok());
|
let tweaked_pk = pk.add_exp_tweak(&s, &tweak).unwrap();
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
assert_ne!(pk, tweaked_pk);
|
||||||
|
|
||||||
|
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
fn test_multiplication() {
|
fn tweak_add_zero() {
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
|
|
||||||
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
|
let (sk, pk) = s.generate_keypair(&mut thread_rng());
|
||||||
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
|
|
||||||
let scalar1 = Scalar::from(sk1);
|
|
||||||
let scalar2 = Scalar::from(sk1);
|
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
let tweak = Scalar::ZERO;
|
||||||
assert!(sk1.mul_assign(&scalar2).is_ok());
|
|
||||||
assert!(pk1.mul_assign(&s, &scalar2).is_ok());
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
let tweaked_sk = sk.add_tweak(&tweak).unwrap();
|
||||||
assert!(sk2.mul_assign(&scalar1).is_ok());
|
assert_eq!(sk, tweaked_sk); // Tweak by zero does nothing.
|
||||||
assert!(pk2.mul_assign(&s, &scalar1).is_ok());
|
let tweaked_pk = pk.add_exp_tweak(&s, &tweak).unwrap();
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
assert_eq!(pk, tweaked_pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "rand-std")]
|
||||||
|
fn tweak_mul_arbitrary_data() {
|
||||||
|
let s = Secp256k1::new();
|
||||||
|
|
||||||
|
let (sk, pk) = s.generate_keypair(&mut thread_rng());
|
||||||
|
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
|
||||||
|
|
||||||
|
// TODO: This would be better tested with a _lot_ of different tweaks.
|
||||||
|
let tweak = Scalar::random();
|
||||||
|
|
||||||
|
let tweaked_sk = sk.mul_tweak(&tweak).unwrap();
|
||||||
|
assert_ne!(sk, tweaked_sk); // Make sure we did something.
|
||||||
|
let tweaked_pk = pk.mul_tweak(&s, &tweak).unwrap();
|
||||||
|
assert_ne!(pk, tweaked_pk);
|
||||||
|
|
||||||
|
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
|
fn tweak_mul_zero() {
|
||||||
|
let s = Secp256k1::new();
|
||||||
|
let (sk, _) = s.generate_keypair(&mut thread_rng());
|
||||||
|
|
||||||
|
let tweak = Scalar::ZERO;
|
||||||
|
assert!(sk.mul_tweak(&tweak).is_err())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
fn test_negation() {
|
fn test_negation() {
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
|
|
||||||
let (mut sk, mut pk) = s.generate_keypair(&mut thread_rng());
|
let (sk, pk) = s.generate_keypair(&mut thread_rng());
|
||||||
|
|
||||||
let original_sk = sk;
|
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
|
||||||
let original_pk = pk;
|
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk);
|
let neg = sk.negate();
|
||||||
sk.negate_assign();
|
assert_ne!(sk, neg);
|
||||||
pk.negate_assign(&s);
|
let back_sk = neg.negate();
|
||||||
assert_ne!(original_sk, sk);
|
assert_eq!(sk, back_sk);
|
||||||
assert_ne!(original_pk, pk);
|
|
||||||
sk.negate_assign();
|
let neg = pk.negate(&s);
|
||||||
pk.negate_assign(&s);
|
assert_ne!(pk, neg);
|
||||||
assert_eq!(original_sk, sk);
|
let back_pk = neg.negate(&s);
|
||||||
assert_eq!(original_pk, pk);
|
assert_eq!(pk, back_pk);
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk);
|
|
||||||
|
assert_eq!(PublicKey::from_secret_key(&s, &back_sk), pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1946,7 +2055,7 @@ mod test {
|
||||||
fn create_pubkey_combine() {
|
fn create_pubkey_combine() {
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
|
|
||||||
let (mut sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
||||||
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());
|
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());
|
||||||
|
|
||||||
let sum1 = pk1.combine(&pk2);
|
let sum1 = pk1.combine(&pk2);
|
||||||
|
@ -1955,8 +2064,8 @@ mod test {
|
||||||
assert!(sum2.is_ok());
|
assert!(sum2.is_ok());
|
||||||
assert_eq!(sum1, sum2);
|
assert_eq!(sum1, sum2);
|
||||||
|
|
||||||
assert!(sk1.add_assign(&Scalar::from(sk2)).is_ok());
|
let tweaked = sk1.add_tweak(&Scalar::from(sk2)).unwrap();
|
||||||
let sksum = PublicKey::from_secret_key(&s, &sk1);
|
let sksum = PublicKey::from_secret_key(&s, &tweaked);
|
||||||
assert_eq!(Ok(sksum), sum1);
|
assert_eq!(Ok(sksum), sum1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2048,23 +2157,27 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
fn test_tweak_add_assign_then_tweak_add_check() {
|
fn test_tweak_add_then_tweak_add_check() {
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
|
|
||||||
|
// TODO: 10 times is arbitrary, we should test this a _lot_ of times.
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
let tweak = Scalar::random();
|
let tweak = Scalar::random();
|
||||||
|
|
||||||
let mut kp = KeyPair::new(&s, &mut thread_rng());
|
let kp = KeyPair::new(&s, &mut thread_rng());
|
||||||
let (mut pk, _parity) = kp.x_only_public_key();
|
let (xonly, _) = XOnlyPublicKey::from_keypair(&kp);
|
||||||
|
|
||||||
let orig_pk = pk;
|
let tweaked_kp = kp.add_xonly_tweak(&s, &tweak).expect("keypair tweak add failed");
|
||||||
kp.tweak_add_assign(&s, &tweak).expect("Tweak error");
|
let (tweaked_xonly, parity) = xonly.add_tweak(&s, &tweak).expect("xonly pubkey tweak failed");
|
||||||
let parity = pk.tweak_add_assign(&s, &tweak).expect("Tweak error");
|
|
||||||
|
|
||||||
let (back, _) = XOnlyPublicKey::from_keypair(&kp);
|
let (want_tweaked_xonly, tweaked_kp_parity) = XOnlyPublicKey::from_keypair(&tweaked_kp);
|
||||||
|
|
||||||
assert_eq!(back, pk);
|
assert_eq!(tweaked_xonly, want_tweaked_xonly);
|
||||||
assert!(orig_pk.tweak_add_check(&s, &pk, parity, tweak));
|
|
||||||
|
#[cfg(not(fuzzing))]
|
||||||
|
assert_eq!(parity, tweaked_kp_parity);
|
||||||
|
|
||||||
|
assert!(xonly.tweak_add_check(&s, &tweaked_xonly, parity, tweak));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -339,7 +339,7 @@ pub enum Error {
|
||||||
InvalidSharedSecret,
|
InvalidSharedSecret,
|
||||||
/// Bad recovery id.
|
/// Bad recovery id.
|
||||||
InvalidRecoveryId,
|
InvalidRecoveryId,
|
||||||
/// Invalid tweak for `add_*_assign` or `mul_*_assign`.
|
/// Tried to add/multiply by an invalid tweak.
|
||||||
InvalidTweak,
|
InvalidTweak,
|
||||||
/// Didn't pass enough memory to context creation with preallocated memory.
|
/// Didn't pass enough memory to context creation with preallocated memory.
|
||||||
NotEnoughMemory,
|
NotEnoughMemory,
|
||||||
|
|
Loading…
Reference in New Issue