Move `XOnlyPublicKey` to `key` module
This commit is contained in:
parent
87d936a765
commit
d4fb819d80
247
src/key.rs
247
src/key.rs
|
@ -17,7 +17,7 @@
|
|||
|
||||
#[cfg(any(test, feature = "rand"))] use rand::Rng;
|
||||
|
||||
use core::{fmt, str};
|
||||
use core::{fmt, ptr, str};
|
||||
|
||||
use super::{from_hex, Secp256k1};
|
||||
use super::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey};
|
||||
|
@ -674,6 +674,251 @@ impl<'a> From<&'a KeyPair> for PublicKey {
|
|||
}
|
||||
}
|
||||
|
||||
/// A x-only public key, used for verification of Schnorr signatures and serialized according to BIP-340.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
|
||||
pub struct XOnlyPublicKey(ffi::XOnlyPublicKey);
|
||||
|
||||
impl fmt::LowerHex for XOnlyPublicKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let ser = self.serialize();
|
||||
for ch in &ser[..] {
|
||||
write!(f, "{:02x}", *ch)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for XOnlyPublicKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::LowerHex::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl str::FromStr for XOnlyPublicKey {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<XOnlyPublicKey, Error> {
|
||||
let mut res = [0u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE];
|
||||
match from_hex(s, &mut res) {
|
||||
Ok(constants::SCHNORRSIG_PUBLIC_KEY_SIZE) => {
|
||||
XOnlyPublicKey::from_slice(&res[0..constants::SCHNORRSIG_PUBLIC_KEY_SIZE])
|
||||
}
|
||||
_ => Err(Error::InvalidPublicKey),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl XOnlyPublicKey {
|
||||
/// Obtains a raw const pointer suitable for use with FFI functions
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const ffi::XOnlyPublicKey {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Obtains a raw mutable pointer suitable for use with FFI functions
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut ffi::XOnlyPublicKey {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
/// Creates a new Schnorr public key from a Schnorr key pair.
|
||||
#[inline]
|
||||
pub fn from_keypair<C: Signing>(secp: &Secp256k1<C>, keypair: &KeyPair) -> XOnlyPublicKey {
|
||||
let mut pk_parity = 0;
|
||||
unsafe {
|
||||
let mut xonly_pk = ffi::XOnlyPublicKey::new();
|
||||
let ret = ffi::secp256k1_keypair_xonly_pub(
|
||||
secp.ctx,
|
||||
&mut xonly_pk,
|
||||
&mut pk_parity,
|
||||
keypair.as_ptr(),
|
||||
);
|
||||
debug_assert_eq!(ret, 1);
|
||||
XOnlyPublicKey(xonly_pk)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a Schnorr public key directly from a slice
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`Error::InvalidPublicKey`] if the length of the data slice is not 32 bytes or the
|
||||
/// 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::SCHNORRSIG_PUBLIC_KEY_SIZE {
|
||||
return Err(Error::InvalidPublicKey);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let mut pk = ffi::XOnlyPublicKey::new();
|
||||
if ffi::secp256k1_xonly_pubkey_parse(
|
||||
ffi::secp256k1_context_no_precomp,
|
||||
&mut pk,
|
||||
data.as_c_ptr(),
|
||||
) == 1
|
||||
{
|
||||
Ok(XOnlyPublicKey(pk))
|
||||
} else {
|
||||
Err(Error::InvalidPublicKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Serialize the key as a byte-encoded x coordinate value (32 bytes).
|
||||
pub fn serialize(&self) -> [u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE] {
|
||||
let mut ret = [0u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE];
|
||||
|
||||
unsafe {
|
||||
let err = ffi::secp256k1_xonly_pubkey_serialize(
|
||||
ffi::secp256k1_context_no_precomp,
|
||||
ret.as_mut_c_ptr(),
|
||||
self.as_c_ptr(),
|
||||
);
|
||||
debug_assert_eq!(err, 1);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
/// Tweak an x-only PublicKey by adding the generator multiplied with the given tweak to it.
|
||||
///
|
||||
/// Returns a boolean representing the parity of the tweaked key, which can be provided to
|
||||
/// `tweak_add_check` which can be used to verify a tweak more efficiently than regenerating
|
||||
/// it and checking equality. Will return an error if the resulting key would be invalid or
|
||||
/// if the tweak was not a 32-byte length slice.
|
||||
pub fn tweak_add_assign<V: Verification>(
|
||||
&mut self,
|
||||
secp: &Secp256k1<V>,
|
||||
tweak: &[u8],
|
||||
) -> Result<bool, Error> {
|
||||
if tweak.len() != 32 {
|
||||
return Err(Error::InvalidTweak);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let mut pubkey = ffi::PublicKey::new();
|
||||
let mut err = ffi::secp256k1_xonly_pubkey_tweak_add(
|
||||
secp.ctx,
|
||||
&mut pubkey,
|
||||
self.as_c_ptr(),
|
||||
tweak.as_c_ptr(),
|
||||
);
|
||||
|
||||
if err != 1 {
|
||||
return Err(Error::InvalidTweak);
|
||||
}
|
||||
|
||||
let mut parity: ::secp256k1_sys::types::c_int = 0;
|
||||
err = ffi::secp256k1_xonly_pubkey_from_pubkey(
|
||||
secp.ctx,
|
||||
&mut self.0,
|
||||
&mut parity,
|
||||
&pubkey,
|
||||
);
|
||||
|
||||
if err == 0 {
|
||||
Err(Error::InvalidPublicKey)
|
||||
} else {
|
||||
Ok(parity != 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify that a tweak produced by `tweak_add_assign` was computed correctly
|
||||
///
|
||||
/// Should be called on the original untweaked key. Takes the tweaked key and
|
||||
/// output parity from `tweak_add_assign` as input.
|
||||
///
|
||||
/// Currently this is not much more efficient than just recomputing the tweak
|
||||
/// and checking equality. However, in future this API will support batch
|
||||
/// verification, which is significantly faster, so it is wise to design
|
||||
/// protocols with this in mind.
|
||||
pub fn tweak_add_check<V: Verification>(
|
||||
&self,
|
||||
secp: &Secp256k1<V>,
|
||||
tweaked_key: &Self,
|
||||
tweaked_parity: bool,
|
||||
tweak: [u8; 32],
|
||||
) -> bool {
|
||||
let tweaked_ser = tweaked_key.serialize();
|
||||
unsafe {
|
||||
let err = ffi::secp256k1_xonly_pubkey_tweak_add_check(
|
||||
secp.ctx,
|
||||
tweaked_ser.as_c_ptr(),
|
||||
if tweaked_parity { 1 } else { 0 },
|
||||
&self.0,
|
||||
tweak.as_c_ptr(),
|
||||
);
|
||||
|
||||
err == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CPtr for XOnlyPublicKey {
|
||||
type Target = ffi::XOnlyPublicKey;
|
||||
fn as_c_ptr(&self) -> *const Self::Target {
|
||||
self.as_ptr()
|
||||
}
|
||||
|
||||
fn as_mut_c_ptr(&mut self) -> *mut Self::Target {
|
||||
self.as_mut_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new Schnorr public key from a FFI x-only public key
|
||||
impl From<ffi::XOnlyPublicKey> for XOnlyPublicKey {
|
||||
#[inline]
|
||||
fn from(pk: ffi::XOnlyPublicKey) -> XOnlyPublicKey {
|
||||
XOnlyPublicKey(pk)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<::key::PublicKey> for XOnlyPublicKey {
|
||||
fn from(src: ::key::PublicKey) -> XOnlyPublicKey {
|
||||
unsafe {
|
||||
let mut pk = ffi::XOnlyPublicKey::new();
|
||||
assert_eq!(
|
||||
1,
|
||||
ffi::secp256k1_xonly_pubkey_from_pubkey(
|
||||
ffi::secp256k1_context_no_precomp,
|
||||
&mut pk,
|
||||
ptr::null_mut(),
|
||||
src.as_c_ptr(),
|
||||
)
|
||||
);
|
||||
XOnlyPublicKey(pk)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl ::serde::Serialize for XOnlyPublicKey {
|
||||
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
if s.is_human_readable() {
|
||||
s.collect_str(self)
|
||||
} else {
|
||||
s.serialize_bytes(&self.serialize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> ::serde::Deserialize<'de> for XOnlyPublicKey {
|
||||
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||
if d.is_human_readable() {
|
||||
d.deserialize_str(super::serde_util::FromStrVisitor::new(
|
||||
"a hex string representing 32 byte schnorr public key"
|
||||
))
|
||||
} else {
|
||||
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
|
||||
"raw 32 bytes schnorr public key",
|
||||
XOnlyPublicKey::from_slice
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use Secp256k1;
|
||||
|
|
|
@ -156,6 +156,7 @@ pub use key::SecretKey;
|
|||
pub use key::PublicKey;
|
||||
pub use key::ONE_KEY;
|
||||
pub use key::KeyPair;
|
||||
pub use key::XOnlyPublicKey;
|
||||
pub use context::*;
|
||||
use core::marker::PhantomData;
|
||||
use core::{mem, fmt, ptr, str};
|
||||
|
|
|
@ -11,8 +11,7 @@ use super::{from_hex, Error};
|
|||
use core::{fmt, ptr, str};
|
||||
use ffi::{self, CPtr};
|
||||
use {constants, Secp256k1};
|
||||
use {Message, Signing, Verification};
|
||||
use KeyPair;
|
||||
use {Message, Signing, KeyPair, XOnlyPublicKey};
|
||||
|
||||
/// Represents a Schnorr signature.
|
||||
pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]);
|
||||
|
@ -74,39 +73,6 @@ impl str::FromStr for Signature {
|
|||
}
|
||||
}
|
||||
|
||||
/// A x-only public key, used for verification of Schnorr signatures
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
|
||||
pub struct XOnlyPublicKey(ffi::XOnlyPublicKey);
|
||||
|
||||
impl fmt::LowerHex for XOnlyPublicKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let ser = self.serialize();
|
||||
for ch in &ser[..] {
|
||||
write!(f, "{:02x}", *ch)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for XOnlyPublicKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::LowerHex::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl str::FromStr for XOnlyPublicKey {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<XOnlyPublicKey, Error> {
|
||||
let mut res = [0u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE];
|
||||
match from_hex(s, &mut res) {
|
||||
Ok(constants::SCHNORRSIG_PUBLIC_KEY_SIZE) => {
|
||||
XOnlyPublicKey::from_slice(&res[0..constants::SCHNORRSIG_PUBLIC_KEY_SIZE])
|
||||
}
|
||||
_ => Err(Error::InvalidPublicKey),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// Creates a Signature directly from a slice
|
||||
#[inline]
|
||||
|
@ -122,218 +88,6 @@ impl Signature {
|
|||
}
|
||||
}
|
||||
|
||||
impl XOnlyPublicKey {
|
||||
/// Obtains a raw const pointer suitable for use with FFI functions
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const ffi::XOnlyPublicKey {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Obtains a raw mutable pointer suitable for use with FFI functions
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut ffi::XOnlyPublicKey {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
/// Creates a new Schnorr public key from a Schnorr key pair.
|
||||
#[inline]
|
||||
pub fn from_keypair<C: Signing>(secp: &Secp256k1<C>, keypair: &KeyPair) -> XOnlyPublicKey {
|
||||
let mut pk_parity = 0;
|
||||
unsafe {
|
||||
let mut xonly_pk = ffi::XOnlyPublicKey::new();
|
||||
let ret = ffi::secp256k1_keypair_xonly_pub(
|
||||
secp.ctx,
|
||||
&mut xonly_pk,
|
||||
&mut pk_parity,
|
||||
keypair.as_ptr(),
|
||||
);
|
||||
debug_assert_eq!(ret, 1);
|
||||
XOnlyPublicKey(xonly_pk)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a Schnorr public key directly from a slice
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`Error::InvalidPublicKey`] if the length of the data slice is not 32 bytes or the
|
||||
/// 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::SCHNORRSIG_PUBLIC_KEY_SIZE {
|
||||
return Err(Error::InvalidPublicKey);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let mut pk = ffi::XOnlyPublicKey::new();
|
||||
if ffi::secp256k1_xonly_pubkey_parse(
|
||||
ffi::secp256k1_context_no_precomp,
|
||||
&mut pk,
|
||||
data.as_c_ptr(),
|
||||
) == 1
|
||||
{
|
||||
Ok(XOnlyPublicKey(pk))
|
||||
} else {
|
||||
Err(Error::InvalidPublicKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Serialize the key as a byte-encoded x coordinate value (32 bytes).
|
||||
pub fn serialize(&self) -> [u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE] {
|
||||
let mut ret = [0u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE];
|
||||
|
||||
unsafe {
|
||||
let err = ffi::secp256k1_xonly_pubkey_serialize(
|
||||
ffi::secp256k1_context_no_precomp,
|
||||
ret.as_mut_c_ptr(),
|
||||
self.as_c_ptr(),
|
||||
);
|
||||
debug_assert_eq!(err, 1);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
/// Tweak an x-only PublicKey by adding the generator multiplied with the given tweak to it.
|
||||
///
|
||||
/// Returns a boolean representing the parity of the tweaked key, which can be provided to
|
||||
/// `tweak_add_check` which can be used to verify a tweak more efficiently than regenerating
|
||||
/// it and checking equality. Will return an error if the resulting key would be invalid or
|
||||
/// if the tweak was not a 32-byte length slice.
|
||||
pub fn tweak_add_assign<V: Verification>(
|
||||
&mut self,
|
||||
secp: &Secp256k1<V>,
|
||||
tweak: &[u8],
|
||||
) -> Result<bool, Error> {
|
||||
if tweak.len() != 32 {
|
||||
return Err(Error::InvalidTweak);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let mut pubkey = ffi::PublicKey::new();
|
||||
let mut err = ffi::secp256k1_xonly_pubkey_tweak_add(
|
||||
secp.ctx,
|
||||
&mut pubkey,
|
||||
self.as_c_ptr(),
|
||||
tweak.as_c_ptr(),
|
||||
);
|
||||
|
||||
if err != 1 {
|
||||
return Err(Error::InvalidTweak);
|
||||
}
|
||||
|
||||
let mut parity: ::secp256k1_sys::types::c_int = 0;
|
||||
err = ffi::secp256k1_xonly_pubkey_from_pubkey(
|
||||
secp.ctx,
|
||||
&mut self.0,
|
||||
&mut parity,
|
||||
&pubkey,
|
||||
);
|
||||
|
||||
if err == 0 {
|
||||
Err(Error::InvalidPublicKey)
|
||||
} else {
|
||||
Ok(parity != 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify that a tweak produced by `tweak_add_assign` was computed correctly
|
||||
///
|
||||
/// Should be called on the original untweaked key. Takes the tweaked key and
|
||||
/// output parity from `tweak_add_assign` as input.
|
||||
///
|
||||
/// Currently this is not much more efficient than just recomputing the tweak
|
||||
/// and checking equality. However, in future this API will support batch
|
||||
/// verification, which is significantly faster, so it is wise to design
|
||||
/// protocols with this in mind.
|
||||
pub fn tweak_add_check<V: Verification>(
|
||||
&self,
|
||||
secp: &Secp256k1<V>,
|
||||
tweaked_key: &Self,
|
||||
tweaked_parity: bool,
|
||||
tweak: [u8; 32],
|
||||
) -> bool {
|
||||
let tweaked_ser = tweaked_key.serialize();
|
||||
unsafe {
|
||||
let err = ffi::secp256k1_xonly_pubkey_tweak_add_check(
|
||||
secp.ctx,
|
||||
tweaked_ser.as_c_ptr(),
|
||||
if tweaked_parity { 1 } else { 0 },
|
||||
&self.0,
|
||||
tweak.as_c_ptr(),
|
||||
);
|
||||
|
||||
err == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CPtr for XOnlyPublicKey {
|
||||
type Target = ffi::XOnlyPublicKey;
|
||||
fn as_c_ptr(&self) -> *const Self::Target {
|
||||
self.as_ptr()
|
||||
}
|
||||
|
||||
fn as_mut_c_ptr(&mut self) -> *mut Self::Target {
|
||||
self.as_mut_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new Schnorr public key from a FFI x-only public key
|
||||
impl From<ffi::XOnlyPublicKey> for XOnlyPublicKey {
|
||||
#[inline]
|
||||
fn from(pk: ffi::XOnlyPublicKey) -> XOnlyPublicKey {
|
||||
XOnlyPublicKey(pk)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<::key::PublicKey> for XOnlyPublicKey {
|
||||
fn from(src: ::key::PublicKey) -> XOnlyPublicKey {
|
||||
unsafe {
|
||||
let mut pk = ffi::XOnlyPublicKey::new();
|
||||
assert_eq!(
|
||||
1,
|
||||
ffi::secp256k1_xonly_pubkey_from_pubkey(
|
||||
ffi::secp256k1_context_no_precomp,
|
||||
&mut pk,
|
||||
ptr::null_mut(),
|
||||
src.as_c_ptr(),
|
||||
)
|
||||
);
|
||||
XOnlyPublicKey(pk)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl ::serde::Serialize for XOnlyPublicKey {
|
||||
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
if s.is_human_readable() {
|
||||
s.collect_str(self)
|
||||
} else {
|
||||
s.serialize_bytes(&self.serialize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> ::serde::Deserialize<'de> for XOnlyPublicKey {
|
||||
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||
if d.is_human_readable() {
|
||||
d.deserialize_str(super::serde_util::FromStrVisitor::new(
|
||||
"a hex string representing 32 byte schnorr public key"
|
||||
))
|
||||
} else {
|
||||
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
|
||||
"raw 32 bytes schnorr public key",
|
||||
XOnlyPublicKey::from_slice
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Signing> Secp256k1<C> {
|
||||
fn schnorrsig_sign_helper(
|
||||
&self,
|
||||
|
|
Loading…
Reference in New Issue