Skip to content

Commit ede62d5

Browse files
committed
Merge #781: feat: Create keys from owned array values
59cf7bd refactor: Create keys from owned array values (Christian Lewe) e7eea32 feat: KeyPair::from_seckey_byte_array (Christian Lewe) e723d80 refactor: Parse byte array instead of byte slice (Christian Lewe) Pull request description: Construct KeyPair directly from [u8; 32]. I can change the parameter to &[u8; 32] depending on the discussion in #780. ACKs for top commit: Kixunil: ACK 59cf7bd apoelstra: ACK 59cf7bd; successfully ran local tests; nice! the old function signatures were super weird. and the docs were wrong lol tcharding: ACK 59cf7bd Tree-SHA512: 64e3026984c79b2491b83775bd50b203ad0723f97ac02b4aa84bc5d0e1135c7fabb660a7d242beaa3f2799f16b169c6bbe3f24e31668518b59ed01839bb86c69
2 parents 0ecd2a2 + 59cf7bd commit ede62d5

File tree

5 files changed

+60
-44
lines changed

5 files changed

+60
-44
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Next
2+
3+
* Create keys from owned array values instead of from references [#781](https://github.com/rust-bitcoin/rust-secp256k1/pull/781)
4+
15
# 0.30.0 - 2024-10-08
26

37
* Allow signing variable-length messages [#706](https://github.com/rust-bitcoin/rust-secp256k1/pull/706)

src/key.rs

+49-37
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ impl str::FromStr for SecretKey {
115115
fn from_str(s: &str) -> Result<SecretKey, Error> {
116116
let mut res = [0u8; constants::SECRET_KEY_SIZE];
117117
match from_hex(s, &mut res) {
118-
Ok(constants::SECRET_KEY_SIZE) => SecretKey::from_byte_array(&res),
118+
Ok(constants::SECRET_KEY_SIZE) => SecretKey::from_byte_array(res),
119119
_ => Err(Error::InvalidSecretKey),
120120
}
121121
}
@@ -138,7 +138,7 @@ impl str::FromStr for SecretKey {
138138
/// use secp256k1::{SecretKey, Secp256k1, PublicKey};
139139
///
140140
/// let secp = Secp256k1::new();
141-
/// let secret_key = SecretKey::from_byte_array(&[0xcd; 32]).expect("32 bytes, within curve order");
141+
/// let secret_key = SecretKey::from_byte_array([0xcd; 32]).expect("32 bytes, within curve order");
142142
/// let public_key = PublicKey::from_secret_key(&secp, &secret_key);
143143
/// # }
144144
/// ```
@@ -175,10 +175,10 @@ impl str::FromStr for PublicKey {
175175
Ok(constants::PUBLIC_KEY_SIZE) => {
176176
let bytes: [u8; constants::PUBLIC_KEY_SIZE] =
177177
res[0..constants::PUBLIC_KEY_SIZE].try_into().unwrap();
178-
PublicKey::from_byte_array_compressed(&bytes)
178+
PublicKey::from_byte_array_compressed(bytes)
179179
}
180180
Ok(constants::UNCOMPRESSED_PUBLIC_KEY_SIZE) =>
181-
PublicKey::from_byte_array_uncompressed(&res),
181+
PublicKey::from_byte_array_uncompressed(res),
182182
_ => Err(Error::InvalidPublicKey),
183183
}
184184
}
@@ -223,7 +223,7 @@ impl SecretKey {
223223
#[inline]
224224
pub fn from_slice(data: &[u8]) -> Result<SecretKey, Error> {
225225
match <[u8; constants::SECRET_KEY_SIZE]>::try_from(data) {
226-
Ok(data) => Self::from_byte_array(&data),
226+
Ok(data) => Self::from_byte_array(data),
227227
Err(_) => Err(InvalidSecretKey),
228228
}
229229
}
@@ -234,18 +234,18 @@ impl SecretKey {
234234
///
235235
/// ```
236236
/// use secp256k1::SecretKey;
237-
/// let sk = SecretKey::from_byte_array(&[0xcd; 32]).expect("32 bytes, within curve order");
237+
/// let sk = SecretKey::from_byte_array([0xcd; 32]).expect("32 bytes, within curve order");
238238
/// ```
239239
#[inline]
240-
pub fn from_byte_array(data: &[u8; constants::SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
240+
pub fn from_byte_array(data: [u8; constants::SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
241241
unsafe {
242242
if ffi::secp256k1_ec_seckey_verify(ffi::secp256k1_context_no_precomp, data.as_c_ptr())
243243
== 0
244244
{
245245
return Err(InvalidSecretKey);
246246
}
247247
}
248-
Ok(SecretKey(*data))
248+
Ok(SecretKey(data))
249249
}
250250

251251
/// Creates a new secret key using data from BIP-340 [`Keypair`].
@@ -373,7 +373,7 @@ impl SecretKey {
373373
impl<T: ThirtyTwoByteHash> From<T> for SecretKey {
374374
/// Converts a 32-byte hash directly to a secret key without error paths.
375375
fn from(t: T) -> SecretKey {
376-
SecretKey::from_byte_array(&t.into_32()).expect("failed to create secret key")
376+
SecretKey::from_byte_array(t.into_32()).expect("failed to create secret key")
377377
}
378378
}
379379

@@ -401,10 +401,10 @@ impl<'de> serde::Deserialize<'de> for SecretKey {
401401
"a hex string representing 32 byte SecretKey",
402402
))
403403
} else {
404-
let visitor = super::serde_util::Tuple32Visitor::new(
405-
"raw 32 bytes SecretKey",
406-
SecretKey::from_slice,
407-
);
404+
let visitor =
405+
super::serde_util::Tuple32Visitor::new("raw 32 bytes SecretKey", |bytes| {
406+
SecretKey::from_byte_array(bytes)
407+
});
408408
d.deserialize_tuple(constants::SECRET_KEY_SIZE, visitor)
409409
}
410410
}
@@ -464,10 +464,10 @@ impl PublicKey {
464464
pub fn from_slice(data: &[u8]) -> Result<PublicKey, Error> {
465465
match data.len() {
466466
constants::PUBLIC_KEY_SIZE => PublicKey::from_byte_array_compressed(
467-
&<[u8; constants::PUBLIC_KEY_SIZE]>::try_from(data).unwrap(),
467+
<[u8; constants::PUBLIC_KEY_SIZE]>::try_from(data).unwrap(),
468468
),
469469
constants::UNCOMPRESSED_PUBLIC_KEY_SIZE => PublicKey::from_byte_array_uncompressed(
470-
&<[u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]>::try_from(data).unwrap(),
470+
<[u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]>::try_from(data).unwrap(),
471471
),
472472
_ => Err(InvalidPublicKey),
473473
}
@@ -476,7 +476,7 @@ impl PublicKey {
476476
/// Creates a public key from a serialized array in compressed format.
477477
#[inline]
478478
pub fn from_byte_array_compressed(
479-
data: &[u8; constants::PUBLIC_KEY_SIZE],
479+
data: [u8; constants::PUBLIC_KEY_SIZE],
480480
) -> Result<PublicKey, Error> {
481481
unsafe {
482482
let mut pk = ffi::PublicKey::new();
@@ -497,7 +497,7 @@ impl PublicKey {
497497
/// Creates a public key from a serialized array in uncompressed format.
498498
#[inline]
499499
pub fn from_byte_array_uncompressed(
500-
data: &[u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE],
500+
data: [u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE],
501501
) -> Result<PublicKey, Error> {
502502
unsafe {
503503
let mut pk = ffi::PublicKey::new();
@@ -553,7 +553,7 @@ impl PublicKey {
553553
};
554554
buf[1..].clone_from_slice(&pk.serialize());
555555

556-
PublicKey::from_byte_array_compressed(&buf).expect("we know the buffer is valid")
556+
PublicKey::from_byte_array_compressed(buf).expect("we know the buffer is valid")
557557
}
558558

559559
#[inline]
@@ -790,10 +790,10 @@ impl<'de> serde::Deserialize<'de> for PublicKey {
790790
"an ASCII hex string representing a public key",
791791
))
792792
} else {
793-
let visitor = super::serde_util::Tuple33Visitor::new(
794-
"33 bytes compressed public key",
795-
PublicKey::from_slice,
796-
);
793+
let visitor =
794+
super::serde_util::Tuple33Visitor::new("33 bytes compressed public key", |bytes| {
795+
PublicKey::from_byte_array_compressed(bytes)
796+
});
797797
d.deserialize_tuple(constants::PUBLIC_KEY_SIZE, visitor)
798798
}
799799
}
@@ -859,16 +859,29 @@ impl Keypair {
859859
/// # Errors
860860
///
861861
/// [`Error::InvalidSecretKey`] if the slice is not exactly 32 bytes long,
862-
/// or if the encoded number exceeds the Secp256k1 field `p` value.
862+
/// or if the encoded number is an invalid scalar.
863+
#[deprecated(since = "TBD", note = "Use `from_seckey_byte_array` instead.")]
863864
#[inline]
864865
pub fn from_seckey_slice<C: Signing>(
865866
secp: &Secp256k1<C>,
866867
data: &[u8],
867868
) -> Result<Keypair, Error> {
868-
if data.is_empty() || data.len() != constants::SECRET_KEY_SIZE {
869-
return Err(Error::InvalidSecretKey);
869+
match <[u8; constants::SECRET_KEY_SIZE]>::try_from(data) {
870+
Ok(data) => Self::from_seckey_byte_array(secp, data),
871+
Err(_) => Err(Error::InvalidSecretKey),
870872
}
873+
}
871874

875+
/// Creates a [`Keypair`] directly from a secret key byte array.
876+
///
877+
/// # Errors
878+
///
879+
/// [`Error::InvalidSecretKey`] if the encoded number is an invalid scalar.
880+
#[inline]
881+
pub fn from_seckey_byte_array<C: Signing>(
882+
secp: &Secp256k1<C>,
883+
data: [u8; constants::SECRET_KEY_SIZE],
884+
) -> Result<Keypair, Error> {
872885
unsafe {
873886
let mut kp = ffi::Keypair::new();
874887
if ffi::secp256k1_keypair_create(secp.ctx.as_ptr(), &mut kp, data.as_c_ptr()) == 1 {
@@ -884,13 +897,12 @@ impl Keypair {
884897
/// # Errors
885898
///
886899
/// [`Error::InvalidSecretKey`] if the string does not consist of exactly 64 hex characters,
887-
/// or if the encoded number exceeds the Secp256k1 field `p` value.
900+
/// or if the encoded number is an invalid scalar.
888901
#[inline]
889902
pub fn from_seckey_str<C: Signing>(secp: &Secp256k1<C>, s: &str) -> Result<Keypair, Error> {
890903
let mut res = [0u8; constants::SECRET_KEY_SIZE];
891904
match from_hex(s, &mut res) {
892-
Ok(constants::SECRET_KEY_SIZE) =>
893-
Keypair::from_seckey_slice(secp, &res[0..constants::SECRET_KEY_SIZE]),
905+
Ok(constants::SECRET_KEY_SIZE) => Keypair::from_seckey_byte_array(secp, res),
894906
_ => Err(Error::InvalidSecretKey),
895907
}
896908
}
@@ -900,7 +912,7 @@ impl Keypair {
900912
/// # Errors
901913
///
902914
/// [`Error::InvalidSecretKey`] if the string does not consist of exactly 64 hex characters,
903-
/// or if the encoded number exceeds the Secp256k1 field `p` value.
915+
/// or if the encoded number is an invalid scalar.
904916
#[inline]
905917
#[cfg(feature = "global-context")]
906918
pub fn from_seckey_str_global(s: &str) -> Result<Keypair, Error> {
@@ -1117,7 +1129,7 @@ impl<'de> serde::Deserialize<'de> for Keypair {
11171129
let ctx = Secp256k1::signing_only();
11181130

11191131
#[allow(clippy::needless_borrow)]
1120-
Keypair::from_seckey_slice(&ctx, data)
1132+
Keypair::from_seckey_byte_array(&ctx, data)
11211133
});
11221134
d.deserialize_tuple(constants::SECRET_KEY_SIZE, visitor)
11231135
}
@@ -1181,7 +1193,7 @@ impl str::FromStr for XOnlyPublicKey {
11811193
fn from_str(s: &str) -> Result<XOnlyPublicKey, Error> {
11821194
let mut res = [0u8; constants::SCHNORR_PUBLIC_KEY_SIZE];
11831195
match from_hex(s, &mut res) {
1184-
Ok(constants::SCHNORR_PUBLIC_KEY_SIZE) => XOnlyPublicKey::from_byte_array(&res),
1196+
Ok(constants::SCHNORR_PUBLIC_KEY_SIZE) => XOnlyPublicKey::from_byte_array(res),
11851197
_ => Err(Error::InvalidPublicKey),
11861198
}
11871199
}
@@ -1231,7 +1243,7 @@ impl XOnlyPublicKey {
12311243
#[inline]
12321244
pub fn from_slice(data: &[u8]) -> Result<XOnlyPublicKey, Error> {
12331245
match <[u8; constants::SCHNORR_PUBLIC_KEY_SIZE]>::try_from(data) {
1234-
Ok(data) => Self::from_byte_array(&data),
1246+
Ok(data) => Self::from_byte_array(data),
12351247
Err(_) => Err(InvalidPublicKey),
12361248
}
12371249
}
@@ -1244,7 +1256,7 @@ impl XOnlyPublicKey {
12441256
/// x coordinate.
12451257
#[inline]
12461258
pub fn from_byte_array(
1247-
data: &[u8; constants::SCHNORR_PUBLIC_KEY_SIZE],
1259+
data: [u8; constants::SCHNORR_PUBLIC_KEY_SIZE],
12481260
) -> Result<XOnlyPublicKey, Error> {
12491261
unsafe {
12501262
let mut pk = ffi::XOnlyPublicKey::new();
@@ -1597,7 +1609,7 @@ impl<'de> serde::Deserialize<'de> for XOnlyPublicKey {
15971609
} else {
15981610
let visitor = super::serde_util::Tuple32Visitor::new(
15991611
"raw 32 bytes schnorr public key",
1600-
XOnlyPublicKey::from_slice,
1612+
XOnlyPublicKey::from_byte_array,
16011613
);
16021614
d.deserialize_tuple(constants::SCHNORR_PUBLIC_KEY_SIZE, visitor)
16031615
}
@@ -1665,7 +1677,7 @@ mod test {
16651677
#[cfg(all(feature = "std", not(secp256k1_fuzz)))]
16661678
fn erased_keypair_is_valid() {
16671679
let s = Secp256k1::new();
1668-
let kp = Keypair::from_seckey_slice(&s, &[1u8; constants::SECRET_KEY_SIZE])
1680+
let kp = Keypair::from_seckey_byte_array(&s, [1u8; constants::SECRET_KEY_SIZE])
16691681
.expect("valid secret key");
16701682
let mut kp2 = kp;
16711683
kp2.non_secure_erase();
@@ -2272,7 +2284,7 @@ mod test {
22722284
];
22732285
static SK_STR: &str = "01010101010101010001020304050607ffff0000ffff00006363636363636363";
22742286

2275-
let sk = Keypair::from_seckey_slice(SECP256K1, &SK_BYTES).unwrap();
2287+
let sk = Keypair::from_seckey_byte_array(SECP256K1, SK_BYTES).unwrap();
22762288
#[rustfmt::skip]
22772289
assert_tokens(&sk.compact(), &[
22782290
Token::Tuple{ len: 32 },
@@ -2452,7 +2464,7 @@ mod test {
24522464

24532465
static PK_STR: &str = "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166";
24542466

2455-
let kp = Keypair::from_seckey_slice(crate::SECP256K1, &SK_BYTES).unwrap();
2467+
let kp = Keypair::from_seckey_byte_array(crate::SECP256K1, SK_BYTES).unwrap();
24562468
let (pk, _parity) = XOnlyPublicKey::from_keypair(&kp);
24572469

24582470
#[rustfmt::skip]

src/schnorr.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ mod tests {
393393
0x63, 0x63, 0x63, 0x63,
394394
];
395395

396-
let kp = Keypair::from_seckey_slice(&secp, &SK_BYTES).expect("sk");
396+
let kp = Keypair::from_seckey_byte_array(&secp, SK_BYTES).expect("sk");
397397

398398
// In fuzzing mode secret->public key derivation is different, so
399399
// hard-code the expected result.
@@ -473,7 +473,7 @@ mod tests {
473473
let s = Secp256k1::new();
474474

475475
let msg = [1; 32];
476-
let keypair = Keypair::from_seckey_slice(&s, &[2; 32]).unwrap();
476+
let keypair = Keypair::from_seckey_byte_array(&s, [2; 32]).unwrap();
477477
let aux = [3u8; 32];
478478
let sig = s.sign_schnorr_with_aux_rand(&msg, &keypair, &aux);
479479
static SIG_BYTES: [u8; constants::SCHNORR_SIGNATURE_SIZE] = [
@@ -706,7 +706,7 @@ mod tests {
706706
} in vectors
707707
{
708708
if let (Some(secret_key), Some(aux_rand)) = (secret_key, aux_rand) {
709-
let keypair = Keypair::from_seckey_slice(&secp, &secret_key).unwrap();
709+
let keypair = Keypair::from_seckey_byte_array(&secp, secret_key).unwrap();
710710
assert_eq!(keypair.x_only_public_key().0.serialize(), public_key);
711711
let sig = secp.sign_schnorr_with_aux_rand(&message, &keypair, &aux_rand);
712712
assert_eq!(sig.to_byte_array(), signature);

src/serde_util.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ macro_rules! impl_tuple_visitor {
7474

7575
impl<F, T, E> $thing<F>
7676
where
77-
F: FnOnce(&[u8]) -> Result<T, E>,
77+
F: FnOnce([u8; $len]) -> Result<T, E>,
7878
E: fmt::Display,
7979
{
8080
pub fn new(expectation: &'static str, parse_fn: F) -> Self {
@@ -84,7 +84,7 @@ macro_rules! impl_tuple_visitor {
8484

8585
impl<'de, F, T, E> de::Visitor<'de> for $thing<F>
8686
where
87-
F: FnOnce(&[u8]) -> Result<T, E>,
87+
F: FnOnce([u8; $len]) -> Result<T, E>,
8888
E: fmt::Display,
8989
{
9090
type Value = T;
@@ -106,7 +106,7 @@ macro_rules! impl_tuple_visitor {
106106
return Err(de::Error::invalid_length(i, &self));
107107
}
108108
}
109-
(self.parse_fn)(&bytes).map_err(de::Error::custom)
109+
(self.parse_fn)(bytes).map_err(de::Error::custom)
110110
}
111111
}
112112
};

tests/serde.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ fn bincode_public_key() {
6161
#[cfg(feature = "global-context")]
6262
fn bincode_keypair() {
6363
let secp = Secp256k1::new();
64-
let kp = Keypair::from_seckey_slice(&secp, &SK_BYTES).expect("failed to create keypair");
64+
let kp = Keypair::from_seckey_byte_array(&secp, SK_BYTES).expect("failed to create keypair");
6565
let ser = bincode::serialize(&kp).unwrap();
6666

6767
assert_eq!(ser, SK_BYTES);

0 commit comments

Comments
 (0)