Skip to content

Commit

Permalink
Add from_byte_array functions
Browse files Browse the repository at this point in the history
Functions have been added to PrivateKey, PublicKey and XOnlyPublicKey to
allow the creation of a key directly from a byte array.
  • Loading branch information
jamillambert committed Sep 11, 2024
1 parent 18654c3 commit 1661f57
Showing 1 changed file with 72 additions and 18 deletions.
90 changes: 72 additions & 18 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ impl SecretKey {
SecretKey(data)
}

/// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key.
/// Converts a 32-byte slice to a secret key.
///
/// # Examples
///
Expand All @@ -214,22 +214,31 @@ impl SecretKey {
#[inline]
pub fn from_slice(data: &[u8]) -> Result<SecretKey, Error> {
match <[u8; constants::SECRET_KEY_SIZE]>::try_from(data) {
Ok(data) => {
unsafe {
if ffi::secp256k1_ec_seckey_verify(
ffi::secp256k1_context_no_precomp,
data.as_c_ptr(),
) == 0
{
return Err(InvalidSecretKey);
}
}
Ok(SecretKey(data))
}
Ok(data) => Self::from_byte_array(&data),
Err(_) => Err(InvalidSecretKey),
}
}

/// Converts a 32-byte array to a secret key.
///
/// # Examples
///
/// ```
/// use secp256k1::SecretKey;
/// let sk = SecretKey::from_byte_array(&[0xcd; 32]).expect("32 bytes, within curve order");
/// ```
#[inline]
pub fn from_byte_array(data: &[u8; constants::SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
unsafe {
if ffi::secp256k1_ec_seckey_verify(ffi::secp256k1_context_no_precomp, data.as_c_ptr())
== 0
{
return Err(InvalidSecretKey);
}
}
Ok(SecretKey(*data))
}

/// Creates a new secret key using data from BIP-340 [`Keypair`].
///
/// # Examples
Expand Down Expand Up @@ -442,17 +451,50 @@ impl PublicKey {
/// Creates a public key directly from a slice.
#[inline]
pub fn from_slice(data: &[u8]) -> Result<PublicKey, Error> {
if data.is_empty() {
return Err(Error::InvalidPublicKey);
match data.len() {
constants::PUBLIC_KEY_SIZE => PublicKey::from_byte_array_compressed(
&<[u8; constants::PUBLIC_KEY_SIZE]>::try_from(data).unwrap(),
),
constants::UNCOMPRESSED_PUBLIC_KEY_SIZE => PublicKey::from_byte_array_uncompressed(
&<[u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]>::try_from(data).unwrap(),
),
_ => Err(InvalidPublicKey),
}
}

/// Creates a public key from a serialized array in compressed format.
#[inline]
pub fn from_byte_array_compressed(
data: &[u8; constants::PUBLIC_KEY_SIZE],
) -> Result<PublicKey, Error> {
unsafe {
let mut pk = ffi::PublicKey::new();
if ffi::secp256k1_ec_pubkey_parse(
ffi::secp256k1_context_no_precomp,
&mut pk,
data.as_c_ptr(),
constants::PUBLIC_KEY_SIZE,
) == 1
{
Ok(PublicKey(pk))
} else {
Err(InvalidPublicKey)
}
}
}

/// Creates a public key from a serialized array in uncompressed format.
#[inline]
pub fn from_byte_array_uncompressed(
data: &[u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE],
) -> Result<PublicKey, Error> {
unsafe {
let mut pk = ffi::PublicKey::new();
if ffi::secp256k1_ec_pubkey_parse(
ffi::secp256k1_context_no_precomp,
&mut pk,
data.as_c_ptr(),
data.len(),
constants::UNCOMPRESSED_PUBLIC_KEY_SIZE,
) == 1
{
Ok(PublicKey(pk))
Expand Down Expand Up @@ -1163,10 +1205,22 @@ impl XOnlyPublicKey {
/// slice does not represent a valid Secp256k1 point x coordinate.
#[inline]
pub fn from_slice(data: &[u8]) -> Result<XOnlyPublicKey, Error> {
if data.is_empty() || data.len() != constants::SCHNORR_PUBLIC_KEY_SIZE {
return Err(Error::InvalidPublicKey);
match <[u8; constants::SCHNORR_PUBLIC_KEY_SIZE]>::try_from(data) {
Ok(data) => Self::from_byte_array(&data),
Err(_) => Err(InvalidPublicKey),
}
}

/// Creates a schnorr public key directly from a byte array.
///
/// # Errors
///
/// Returns [`Error::InvalidPublicKey`] if the array does not represent a valid Secp256k1 point
/// x coordinate.
#[inline]
pub fn from_byte_array(
data: &[u8; constants::SCHNORR_PUBLIC_KEY_SIZE],
) -> Result<XOnlyPublicKey, Error> {
unsafe {
let mut pk = ffi::XOnlyPublicKey::new();
if ffi::secp256k1_xonly_pubkey_parse(
Expand Down

0 comments on commit 1661f57

Please sign in to comment.