Add parity argument to XOnlyPublicKey::from_secp
What changed, and why it matters
This commit is a small API cleanup in a Rust Bitcoin library. It changes one constructor so callers must provide a 'parity' value directly instead of setting it afterward. Existing callers are updated to preserve the same behavior as before. There is no indication this fixes a security bug or changes any security-relevant behavior.
No security action required. Treat as a normal API refactor. Downstream users updating to this version should note the changed signature of XOnlyPublicKey::from_secp and supply the required Parity argument.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch modifies XOnlyPublicKey::from_secp in rust-bitcoin to accept an explicit Parity argument rather than defaulting to Even and requiring a separate with_parity() call. All internal call sites are updated to pass the same parity they previously set via with_parity(), and conversion traits that lack parity information continue to default to Even. The change is purely refactor/ergonomic and does not alter cryptographic semantics.
Changed components
bitcoin/src/crypto/key.rsXOnlyPublicKey::from_secpXOnlyPublicKey::from_keypairXOnlyPublicKey::from_byte_arrayXOnlyPublicKey::add_tweakFrom<secp256k1::XOnlyPublicKey> for XOnlyPublicKeyFrom<secp256k1::PublicKey> for XOnlyPublicKeyDeserialize for XOnlyPublicKeyFrom<PublicKey> for XOnlyPublicKeyInspect captured patch +10 / −10
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index 93ed7bb9..ad385140 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -55,8 +55,8 @@ mod encapsulate {
///
/// This constructor sets an even parity. Use [`XOnlyPublicKey::with_parity`] if you need
/// a different parity value.
- pub fn from_secp(key: impl Into<secp256k1::XOnlyPublicKey>) -> Self {
- Self { inner: key.into(), parity: Parity::Even }
+ pub fn from_secp(key: impl Into<secp256k1::XOnlyPublicKey>, parity: Parity) -> Self {
+ Self { inner: key.into(), parity }
}
/// Sets the parity of this [`XOnlyPublicKey`].
@@ -283,7 +283,7 @@ impl XOnlyPublicKey {
#[inline]
pub fn from_keypair(keypair: &Keypair) -> Self {
let (xonly, parity) = secp256k1::XOnlyPublicKey::from_keypair(&keypair.to_inner());
- Self::from_secp(xonly).with_parity(parity)
+ Self::from_secp(xonly, parity)
}
/// Constructs an x-only public key from a 32-byte x-coordinate.
@@ -296,7 +296,7 @@ impl XOnlyPublicKey {
data: &[u8; constants::SCHNORR_PUBLIC_KEY_SIZE],
) -> Result<Self, ParseXOnlyPublicKeyError> {
secp256k1::XOnlyPublicKey::from_byte_array(*data)
- .map(Self::from_secp)
+ .map(|key| Self::from_secp(key, Parity::Even))
.map_err(|_| ParseXOnlyPublicKeyError::InvalidXCoordinate)
}
@@ -339,7 +339,7 @@ impl XOnlyPublicKey {
#[inline]
pub fn add_tweak(&self, tweak: &secp256k1::Scalar) -> Result<Self, TweakXOnlyPublicKeyError> {
match self.as_inner().add_tweak(tweak) {
- Ok((xonly, parity)) => Ok(Self::from_secp(xonly).with_parity(parity)),
+ Ok((xonly, parity)) => Ok(Self::from_secp(xonly, parity)),
Err(secp256k1::Error::InvalidTweak) => Err(TweakXOnlyPublicKeyError::BadTweak),
Err(secp256k1::Error::InvalidParityValue(_)) =>
Err(TweakXOnlyPublicKeyError::ParityError),
@@ -358,13 +358,13 @@ impl FromStr for XOnlyPublicKey {
}
impl From<secp256k1::XOnlyPublicKey> for XOnlyPublicKey {
- fn from(pk: secp256k1::XOnlyPublicKey) -> Self { Self::from_secp(pk) }
+ fn from(pk: secp256k1::XOnlyPublicKey) -> Self { Self::from_secp(pk, Parity::Even) }
}
impl From<secp256k1::PublicKey> for XOnlyPublicKey {
fn from(pk: secp256k1::PublicKey) -> Self {
let (xonly, parity) = pk.x_only_public_key();
- Self::from_secp(xonly).with_parity(parity)
+ Self::from_secp(xonly, parity)
}
}
@@ -395,7 +395,7 @@ impl<'de> Deserialize<'de> for XOnlyPublicKey {
where
D: Deserializer<'de>,
{
- Ok(Self::from_secp(secp256k1::XOnlyPublicKey::deserialize(deserializer)?))
+ Ok(Self::from_secp(secp256k1::XOnlyPublicKey::deserialize(deserializer)?, Parity::Even))
}
}
@@ -685,7 +685,7 @@ impl From<secp256k1::PublicKey> for PublicKey {
impl From<PublicKey> for XOnlyPublicKey {
fn from(pk: PublicKey) -> Self {
let (xonly, parity) = pk.to_inner().x_only_public_key();
- Self::from_secp(xonly).with_parity(parity)
+ Self::from_secp(xonly, parity)
}
}
@@ -2149,7 +2149,7 @@ mod tests {
.expect("Failed to convert hex string to byte array");
let inner_key = secp256k1::XOnlyPublicKey::from_byte_array(*key_bytes)
.expect("Failed to create a secp256k1 x-only public key from a byte array");
- let btc_pubkey = XOnlyPublicKey::from_secp(inner_key);
+ let btc_pubkey = XOnlyPublicKey::from(inner_key);
// Confirm that the to_inner() returns the same data that was initially wrapped
assert_eq!(inner_key, btc_pubkey.to_inner());
}
Why this scored 19/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.