From e7eea32ffaf36172a03063b634a435ec937b7d21 Mon Sep 17 00:00:00 2001 From: Christian Lewe Date: Sat, 15 Feb 2025 22:56:02 +0100 Subject: [PATCH] feat: KeyPair::from_seckey_byte_array Construct KeyPair directly from [u8; 32]. Deprecate KeyPair::from_seckey_slice and replace all of its calls with the new method. --- src/key.rs | 34 +++++++++++++++++++++++----------- src/schnorr.rs | 6 +++--- tests/serde.rs | 2 +- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/key.rs b/src/key.rs index 3d18871eb..65ed7b545 100644 --- a/src/key.rs +++ b/src/key.rs @@ -859,16 +859,29 @@ impl Keypair { /// # Errors /// /// [`Error::InvalidSecretKey`] if the slice is not exactly 32 bytes long, - /// or if the encoded number exceeds the Secp256k1 field `p` value. + /// or if the encoded number is an invalid scalar. + #[deprecated(since = "TBD", note = "Use `from_seckey_byte_array` instead.")] #[inline] pub fn from_seckey_slice( secp: &Secp256k1, data: &[u8], ) -> Result { - if data.is_empty() || data.len() != constants::SECRET_KEY_SIZE { - return Err(Error::InvalidSecretKey); + match <[u8; constants::SECRET_KEY_SIZE]>::try_from(data) { + Ok(data) => Self::from_seckey_byte_array(secp, data), + Err(_) => Err(Error::InvalidSecretKey), } + } + /// Creates a [`Keypair`] directly from a secret key byte array. + /// + /// # Errors + /// + /// [`Error::InvalidSecretKey`] if the encoded number is an invalid scalar. + #[inline] + pub fn from_seckey_byte_array( + secp: &Secp256k1, + data: [u8; constants::SECRET_KEY_SIZE], + ) -> Result { unsafe { let mut kp = ffi::Keypair::new(); if ffi::secp256k1_keypair_create(secp.ctx.as_ptr(), &mut kp, data.as_c_ptr()) == 1 { @@ -884,13 +897,12 @@ impl Keypair { /// # Errors /// /// [`Error::InvalidSecretKey`] if the string does not consist of exactly 64 hex characters, - /// or if the encoded number exceeds the Secp256k1 field `p` value. + /// or if the encoded number is an invalid scalar. #[inline] pub fn from_seckey_str(secp: &Secp256k1, s: &str) -> Result { let mut res = [0u8; constants::SECRET_KEY_SIZE]; match from_hex(s, &mut res) { - Ok(constants::SECRET_KEY_SIZE) => - Keypair::from_seckey_slice(secp, &res[0..constants::SECRET_KEY_SIZE]), + Ok(constants::SECRET_KEY_SIZE) => Keypair::from_seckey_byte_array(secp, res), _ => Err(Error::InvalidSecretKey), } } @@ -900,7 +912,7 @@ impl Keypair { /// # Errors /// /// [`Error::InvalidSecretKey`] if the string does not consist of exactly 64 hex characters, - /// or if the encoded number exceeds the Secp256k1 field `p` value. + /// or if the encoded number is an invalid scalar. #[inline] #[cfg(feature = "global-context")] pub fn from_seckey_str_global(s: &str) -> Result { @@ -1117,7 +1129,7 @@ impl<'de> serde::Deserialize<'de> for Keypair { let ctx = Secp256k1::signing_only(); #[allow(clippy::needless_borrow)] - Keypair::from_seckey_slice(&ctx, &data) + Keypair::from_seckey_byte_array(&ctx, data) }); d.deserialize_tuple(constants::SECRET_KEY_SIZE, visitor) } @@ -1665,7 +1677,7 @@ mod test { #[cfg(all(feature = "std", not(secp256k1_fuzz)))] fn erased_keypair_is_valid() { let s = Secp256k1::new(); - let kp = Keypair::from_seckey_slice(&s, &[1u8; constants::SECRET_KEY_SIZE]) + let kp = Keypair::from_seckey_byte_array(&s, [1u8; constants::SECRET_KEY_SIZE]) .expect("valid secret key"); let mut kp2 = kp; kp2.non_secure_erase(); @@ -2272,7 +2284,7 @@ mod test { ]; static SK_STR: &str = "01010101010101010001020304050607ffff0000ffff00006363636363636363"; - let sk = Keypair::from_seckey_slice(SECP256K1, &SK_BYTES).unwrap(); + let sk = Keypair::from_seckey_byte_array(SECP256K1, SK_BYTES).unwrap(); #[rustfmt::skip] assert_tokens(&sk.compact(), &[ Token::Tuple{ len: 32 }, @@ -2452,7 +2464,7 @@ mod test { static PK_STR: &str = "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"; - let kp = Keypair::from_seckey_slice(crate::SECP256K1, &SK_BYTES).unwrap(); + let kp = Keypair::from_seckey_byte_array(crate::SECP256K1, SK_BYTES).unwrap(); let (pk, _parity) = XOnlyPublicKey::from_keypair(&kp); #[rustfmt::skip] diff --git a/src/schnorr.rs b/src/schnorr.rs index e83bd8fec..e4a07a305 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -393,7 +393,7 @@ mod tests { 0x63, 0x63, 0x63, 0x63, ]; - let kp = Keypair::from_seckey_slice(&secp, &SK_BYTES).expect("sk"); + let kp = Keypair::from_seckey_byte_array(&secp, SK_BYTES).expect("sk"); // In fuzzing mode secret->public key derivation is different, so // hard-code the expected result. @@ -473,7 +473,7 @@ mod tests { let s = Secp256k1::new(); let msg = [1; 32]; - let keypair = Keypair::from_seckey_slice(&s, &[2; 32]).unwrap(); + let keypair = Keypair::from_seckey_byte_array(&s, [2; 32]).unwrap(); let aux = [3u8; 32]; let sig = s.sign_schnorr_with_aux_rand(&msg, &keypair, &aux); static SIG_BYTES: [u8; constants::SCHNORR_SIGNATURE_SIZE] = [ @@ -706,7 +706,7 @@ mod tests { } in vectors { if let (Some(secret_key), Some(aux_rand)) = (secret_key, aux_rand) { - let keypair = Keypair::from_seckey_slice(&secp, &secret_key).unwrap(); + let keypair = Keypair::from_seckey_byte_array(&secp, secret_key).unwrap(); assert_eq!(keypair.x_only_public_key().0.serialize(), public_key); let sig = secp.sign_schnorr_with_aux_rand(&message, &keypair, &aux_rand); assert_eq!(sig.to_byte_array(), signature); diff --git a/tests/serde.rs b/tests/serde.rs index 083514bc2..3b8df3915 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -61,7 +61,7 @@ fn bincode_public_key() { #[cfg(feature = "global-context")] fn bincode_keypair() { let secp = Secp256k1::new(); - let kp = Keypair::from_seckey_slice(&secp, &SK_BYTES).expect("failed to create keypair"); + let kp = Keypair::from_seckey_byte_array(&secp, SK_BYTES).expect("failed to create keypair"); let ser = bincode::serialize(&kp).unwrap(); assert_eq!(ser, SK_BYTES);