Skip to content

Commit aab77b1

Browse files
committed
Merge #445: Add Scalar newtype and use it in tweaking APIs
5a03324 Add `Scalar` newtype and use it in tweaking APIs (Martin Habovstiak) Pull request description: This adds `Scalar` newtype to better represent values accepted by tweaking functions. This type is always 32-bytes and guarantees being within curve order. This is an initial iteration. Things I'm not 100% sure of, would appreciate help: * Is it actually required for scalar to be within curve order? * Are non-constant-time operations actually an issue? Alterntive tweaking API designs: * Accept `Into<Scalar>` generic argument, so people can pass `SecretKey`, may slightly worsen performance * `unsafe`-ly implement `AsRef<Scalar> for SecretKey` (casting raw pointers) and accept that Possible extension: API to convert from slices so that the user doesn't need two steps (convert to array first). ACKs for top commit: apoelstra: ACK 5a03324 Tree-SHA512: cf639c91f0c6f6e0178d8a6d4125fd041708a59661fbd2f1924881001011e4cfe2b998148ae652995cdc9a3791c6644fcd5f004e059d76d9182a5e409b791446
2 parents 4f7f138 + 5a03324 commit aab77b1

File tree

3 files changed

+174
-58
lines changed

3 files changed

+174
-58
lines changed

src/key.rs

+35-58
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use crate::ffi::types::c_uint;
2929
use crate::{Message, ecdsa, SECP256K1};
3030
#[cfg(all(feature = "global-context", feature = "rand-std"))]
3131
use crate::schnorr;
32+
use crate::Scalar;
3233

3334
/// Secret 256-bit key used as `x` in an ECDSA signature.
3435
///
@@ -232,15 +233,11 @@ impl SecretKey {
232233
///
233234
/// # Errors
234235
///
235-
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
236-
/// length slice.
236+
/// Returns an error if the resulting key would be invalid.
237237
pub fn add_assign(
238238
&mut self,
239-
other: &[u8],
239+
other: &Scalar,
240240
) -> Result<(), Error> {
241-
if other.len() != 32 {
242-
return Err(Error::InvalidTweak);
243-
}
244241
unsafe {
245242
if ffi::secp256k1_ec_seckey_tweak_add(
246243
ffi::secp256k1_context_no_precomp,
@@ -257,15 +254,11 @@ impl SecretKey {
257254

258255
#[inline]
259256
/// Multiplies one secret key by another, modulo the curve order. Will
260-
/// return an error if the resulting key would be invalid or if
261-
/// the tweak was not a 32-byte length slice.
257+
/// return an error if the resulting key would be invalid.
262258
pub fn mul_assign(
263259
&mut self,
264-
other: &[u8],
260+
other: &Scalar,
265261
) -> Result<(), Error> {
266-
if other.len() != 32 {
267-
return Err(Error::InvalidTweak);
268-
}
269262
unsafe {
270263
if ffi::secp256k1_ec_seckey_tweak_mul(
271264
ffi::secp256k1_context_no_precomp,
@@ -498,20 +491,16 @@ impl PublicKey {
498491
}
499492

500493
#[inline]
501-
/// Adds the `other` public key to `self` in place.
494+
/// Adds `other * G` to `self` in place.
502495
///
503496
/// # Errors
504497
///
505-
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
506-
/// length slice.
498+
/// Returns an error if the resulting key would be invalid.
507499
pub fn add_exp_assign<C: Verification>(
508500
&mut self,
509501
secp: &Secp256k1<C>,
510-
other: &[u8]
502+
other: &Scalar
511503
) -> Result<(), Error> {
512-
if other.len() != 32 {
513-
return Err(Error::InvalidTweak);
514-
}
515504
unsafe {
516505
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
517506
Ok(())
@@ -526,16 +515,12 @@ impl PublicKey {
526515
///
527516
/// # Errors
528517
///
529-
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
530-
/// length slice.
518+
/// Returns an error if the resulting key would be invalid.
531519
pub fn mul_assign<C: Verification>(
532520
&mut self,
533521
secp: &Secp256k1<C>,
534-
other: &[u8],
522+
other: &Scalar,
535523
) -> Result<(), Error> {
536-
if other.len() != 32 {
537-
return Err(Error::InvalidTweak);
538-
}
539524
unsafe {
540525
if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
541526
Ok(())
@@ -860,8 +845,7 @@ impl KeyPair {
860845
///
861846
/// # Errors
862847
///
863-
/// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte
864-
/// length slice.
848+
/// Returns an error if the resulting key would be invalid.
865849
///
866850
/// NB: Will not error if the tweaked public key has an odd value and can't be used for
867851
/// BIP 340-342 purposes.
@@ -870,12 +854,11 @@ impl KeyPair {
870854
///
871855
/// ```
872856
/// # #[cfg(all(feature = "std", feature = "rand-std"))] {
873-
/// use secp256k1::{Secp256k1, KeyPair};
857+
/// use secp256k1::{Secp256k1, KeyPair, Scalar};
874858
/// use secp256k1::rand::{RngCore, thread_rng};
875859
///
876860
/// let secp = Secp256k1::new();
877-
/// let mut tweak = [0u8; 32];
878-
/// thread_rng().fill_bytes(&mut tweak);
861+
/// let tweak = Scalar::random();
879862
///
880863
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
881864
/// key_pair.tweak_add_assign(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak");
@@ -886,12 +869,8 @@ impl KeyPair {
886869
pub fn tweak_add_assign<C: Verification>(
887870
&mut self,
888871
secp: &Secp256k1<C>,
889-
tweak: &[u8],
872+
tweak: &Scalar,
890873
) -> Result<(), Error> {
891-
if tweak.len() != 32 {
892-
return Err(Error::InvalidTweak);
893-
}
894-
895874
unsafe {
896875
let err = ffi::secp256k1_keypair_xonly_tweak_add(
897876
secp.ctx,
@@ -1150,12 +1129,11 @@ impl XOnlyPublicKey {
11501129
///
11511130
/// ```
11521131
/// # #[cfg(all(feature = "std", feature = "rand-std"))] {
1153-
/// use secp256k1::{Secp256k1, KeyPair};
1132+
/// use secp256k1::{Secp256k1, KeyPair, Scalar};
11541133
/// use secp256k1::rand::{RngCore, thread_rng};
11551134
///
11561135
/// let secp = Secp256k1::new();
1157-
/// let mut tweak = [0u8; 32];
1158-
/// thread_rng().fill_bytes(&mut tweak);
1136+
/// let tweak = Scalar::random();
11591137
///
11601138
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
11611139
/// let (mut public_key, _parity) = key_pair.x_only_public_key();
@@ -1165,12 +1143,8 @@ impl XOnlyPublicKey {
11651143
pub fn tweak_add_assign<V: Verification>(
11661144
&mut self,
11671145
secp: &Secp256k1<V>,
1168-
tweak: &[u8],
1146+
tweak: &Scalar,
11691147
) -> Result<Parity, Error> {
1170-
if tweak.len() != 32 {
1171-
return Err(Error::InvalidTweak);
1172-
}
1173-
11741148
let mut pk_parity = 0;
11751149
unsafe {
11761150
let mut pubkey = ffi::PublicKey::new();
@@ -1215,12 +1189,11 @@ impl XOnlyPublicKey {
12151189
///
12161190
/// ```
12171191
/// # #[cfg(all(feature = "std", feature = "rand-std"))] {
1218-
/// use secp256k1::{Secp256k1, KeyPair};
1192+
/// use secp256k1::{Secp256k1, KeyPair, Scalar};
12191193
/// use secp256k1::rand::{thread_rng, RngCore};
12201194
///
12211195
/// let secp = Secp256k1::new();
1222-
/// let mut tweak = [0u8; 32];
1223-
/// thread_rng().fill_bytes(&mut tweak);
1196+
/// let tweak = Scalar::random();
12241197
///
12251198
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
12261199
/// let (mut public_key, _) = key_pair.x_only_public_key();
@@ -1234,7 +1207,7 @@ impl XOnlyPublicKey {
12341207
secp: &Secp256k1<V>,
12351208
tweaked_key: &Self,
12361209
tweaked_parity: Parity,
1237-
tweak: [u8; 32],
1210+
tweak: Scalar,
12381211
) -> bool {
12391212
let tweaked_ser = tweaked_key.serialize();
12401213
unsafe {
@@ -1512,6 +1485,7 @@ mod test {
15121485
use super::{XOnlyPublicKey, PublicKey, Secp256k1, SecretKey, KeyPair, Parity};
15131486
use crate::{constants, from_hex, to_hex};
15141487
use crate::Error::{InvalidPublicKey, InvalidSecretKey};
1488+
use crate::Scalar;
15151489

15161490
macro_rules! hex {
15171491
($hex:expr) => ({
@@ -1770,15 +1744,17 @@ mod test {
17701744

17711745
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
17721746
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
1747+
let scalar1 = Scalar::from(sk1);
1748+
let scalar2 = Scalar::from(sk1);
17731749

17741750
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());
1751+
assert!(sk1.add_assign(&scalar2).is_ok());
1752+
assert!(pk1.add_exp_assign(&s, &scalar2).is_ok());
17771753
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
17781754

17791755
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());
1756+
assert!(sk2.add_assign(&scalar1).is_ok());
1757+
assert!(pk2.add_exp_assign(&s, &scalar1).is_ok());
17821758
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
17831759
}
17841760

@@ -1789,15 +1765,17 @@ mod test {
17891765

17901766
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng());
17911767
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
1768+
let scalar1 = Scalar::from(sk1);
1769+
let scalar2 = Scalar::from(sk1);
17921770

17931771
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());
1772+
assert!(sk1.mul_assign(&scalar2).is_ok());
1773+
assert!(pk1.mul_assign(&s, &scalar2).is_ok());
17961774
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
17971775

17981776
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());
1777+
assert!(sk2.mul_assign(&scalar1).is_ok());
1778+
assert!(pk2.mul_assign(&s, &scalar1).is_ok());
18011779
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
18021780
}
18031781

@@ -1913,7 +1891,7 @@ mod test {
19131891
assert!(sum2.is_ok());
19141892
assert_eq!(sum1, sum2);
19151893

1916-
assert!(sk1.add_assign(&sk2.as_ref()[..]).is_ok());
1894+
assert!(sk1.add_assign(&Scalar::from(sk2)).is_ok());
19171895
let sksum = PublicKey::from_secret_key(&s, &sk1);
19181896
assert_eq!(Ok(sksum), sum1);
19191897
}
@@ -1999,8 +1977,7 @@ mod test {
19991977
let s = Secp256k1::new();
20001978

20011979
for _ in 0..10 {
2002-
let mut tweak = [0u8; 32];
2003-
thread_rng().fill_bytes(&mut tweak);
1980+
let tweak = Scalar::random();
20041981

20051982
let mut kp = KeyPair::new(&s, &mut thread_rng());
20061983
let (mut pk, _parity) = kp.x_only_public_key();

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ mod key;
173173
pub mod constants;
174174
pub mod ecdh;
175175
pub mod ecdsa;
176+
pub mod scalar;
176177
pub mod schnorr;
177178
#[cfg(feature = "serde")]
178179
mod serde_util;
@@ -190,6 +191,7 @@ pub use secp256k1_sys as ffi;
190191
pub use crate::key::{PublicKey, SecretKey};
191192
pub use crate::context::*;
192193
pub use crate::key::*;
194+
pub use crate::scalar::Scalar;
193195

194196
#[cfg(feature = "global-context")]
195197
#[cfg_attr(docsrs, doc(cfg(feature = "global-context")))]

0 commit comments

Comments
 (0)