Merge rust-bitcoin/rust-secp256k1#327: Re-arrange functionality to make ECDSA and Schnorr equal-ish citizens

d244b4d747 Fix typo in docs (Thomas Eizinger)
c5c95513f2 Move helper function below usage (Thomas Eizinger)
ce4427747d Move ECDSA functionality into ECDSA module (Thomas Eizinger)
e0c3bb28c4 Rename schnorr functions on `Secp256k1` to match naming of ecdsa (Thomas Eizinger)
760559c70e Rename `schnorrsig` module to `schnorr` (Thomas Eizinger)
d4fb819d80 Move `XOnlyPublicKey` to `key` module (Thomas Eizinger)
87d936a765 Rename `schnorr::PublicKey` to `schnorr::XOnlyPublicKey` (Thomas Eizinger)
2e0e731664 Move `KeyPair` to `key` module (Thomas Eizinger)
c47ead9967 Move `Signature` and `SerializedSignature` to new `ecdsa` module (Thomas Eizinger)
49c7e21486 Prefer `use super::*` import over manually picking items (Thomas Eizinger)
52d0554423 Fully qualify Error to simplify imports (Thomas Eizinger)
8e96abae39 Make `key` module private (Thomas Eizinger)

Pull request description:

  This patch-set tries to re-structure the library a bit. What we currently have seems to have been mostly driven by historical growth. For example, with the addition of Schnorr signatures, just exposing `secp256k1::Signature` is ambiguous.

  This PR only contains renames and moving around of code. I've tried to structure the patches in such a way that makes this reasonably easy to review. Feedback welcome!

ACKs for top commit:
  sanket1729:
    ACK d244b4d747
  apoelstra:
    ACK d244b4d747

Tree-SHA512: d40af5c56ffa500305e40eb5dbe72f2f6d6193b3a190910018d3bacdec2820ab6a59f15d47d11e0fee7ef4de6efd46d316636cd502aad5db4f314dedfff726f9
This commit is contained in:
Andrew Poelstra 2021-11-12 13:04:40 +00:00
commit 48683d87c8
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
10 changed files with 1172 additions and 1046 deletions

View File

@ -2,22 +2,22 @@ extern crate bitcoin_hashes;
extern crate secp256k1; extern crate secp256k1;
use bitcoin_hashes::{sha256, Hash}; use bitcoin_hashes::{sha256, Hash};
use secp256k1::{Error, Message, PublicKey, Secp256k1, SecretKey, Signature, Signing, Verification}; use secp256k1::{Error, Message, PublicKey, Secp256k1, SecretKey, ecdsa, Signing, Verification};
fn verify<C: Verification>(secp: &Secp256k1<C>, msg: &[u8], sig: [u8; 64], pubkey: [u8; 33]) -> Result<bool, Error> { fn verify<C: Verification>(secp: &Secp256k1<C>, msg: &[u8], sig: [u8; 64], pubkey: [u8; 33]) -> Result<bool, Error> {
let msg = sha256::Hash::hash(msg); let msg = sha256::Hash::hash(msg);
let msg = Message::from_slice(&msg)?; let msg = Message::from_slice(&msg)?;
let sig = Signature::from_compact(&sig)?; let sig = ecdsa::Signature::from_compact(&sig)?;
let pubkey = PublicKey::from_slice(&pubkey)?; let pubkey = PublicKey::from_slice(&pubkey)?;
Ok(secp.verify(&msg, &sig, &pubkey).is_ok()) Ok(secp.verify_ecdsa(&msg, &sig, &pubkey).is_ok())
} }
fn sign<C: Signing>(secp: &Secp256k1<C>, msg: &[u8], seckey: [u8; 32]) -> Result<Signature, Error> { fn sign<C: Signing>(secp: &Secp256k1<C>, msg: &[u8], seckey: [u8; 32]) -> Result<ecdsa::Signature, Error> {
let msg = sha256::Hash::hash(msg); let msg = sha256::Hash::hash(msg);
let msg = Message::from_slice(&msg)?; let msg = Message::from_slice(&msg)?;
let seckey = SecretKey::from_slice(&seckey)?; let seckey = SecretKey::from_slice(&seckey)?;
Ok(secp.sign(&msg, &seckey)) Ok(secp.sign_ecdsa(&msg, &seckey))
} }
fn main() { fn main() {

View File

@ -3,23 +3,22 @@ extern crate bitcoin_hashes;
extern crate secp256k1; extern crate secp256k1;
use bitcoin_hashes::{sha256, Hash}; use bitcoin_hashes::{sha256, Hash};
use secp256k1::recovery::{RecoverableSignature, RecoveryId}; use secp256k1::{Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification, ecdsa};
use secp256k1::{Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification};
fn recover<C: Verification>(secp: &Secp256k1<C>,msg: &[u8],sig: [u8; 64],recovery_id: u8) -> Result<PublicKey, Error> { fn recover<C: Verification>(secp: &Secp256k1<C>,msg: &[u8],sig: [u8; 64],recovery_id: u8) -> Result<PublicKey, Error> {
let msg = sha256::Hash::hash(msg); let msg = sha256::Hash::hash(msg);
let msg = Message::from_slice(&msg)?; let msg = Message::from_slice(&msg)?;
let id = RecoveryId::from_i32(recovery_id as i32)?; let id = ecdsa::RecoveryId::from_i32(recovery_id as i32)?;
let sig = RecoverableSignature::from_compact(&sig, id)?; let sig = ecdsa::RecoverableSignature::from_compact(&sig, id)?;
secp.recover(&msg, &sig) secp.recover_ecdsa(&msg, &sig)
} }
fn sign_recovery<C: Signing>(secp: &Secp256k1<C>, msg: &[u8], seckey: [u8; 32]) -> Result<RecoverableSignature, Error> { fn sign_recovery<C: Signing>(secp: &Secp256k1<C>, msg: &[u8], seckey: [u8; 32]) -> Result<ecdsa::RecoverableSignature, Error> {
let msg = sha256::Hash::hash(msg); let msg = sha256::Hash::hash(msg);
let msg = Message::from_slice(&msg)?; let msg = Message::from_slice(&msg)?;
let seckey = SecretKey::from_slice(&seckey)?; let seckey = SecretKey::from_slice(&seckey)?;
Ok(secp.sign_recoverable(&msg, &seckey)) Ok(secp.sign_ecdsa_recoverable(&msg, &seckey))
} }
fn main() { fn main() {

View File

@ -106,14 +106,14 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
let public_key = PublicKey::from_secret_key(&secp, &secret_key); let public_key = PublicKey::from_secret_key(&secp, &secret_key);
let message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
let sig = secp.sign(&message, &secret_key); let sig = secp.sign_ecdsa(&message, &secret_key);
assert!(secp.verify(&message, &sig, &public_key).is_ok()); assert!(secp.verify_ecdsa(&message, &sig, &public_key).is_ok());
let rec_sig = secp.sign_recoverable(&message, &secret_key); let rec_sig = secp.sign_ecdsa_recoverable(&message, &secret_key);
assert!(secp.verify(&message, &rec_sig.to_standard(), &public_key).is_ok()); assert!(secp.verify_ecdsa(&message, &rec_sig.to_standard(), &public_key).is_ok());
assert_eq!(public_key, secp.recover(&message, &rec_sig).unwrap()); assert_eq!(public_key, secp.recover_ecdsa(&message, &rec_sig).unwrap());
let (rec_id, data) = rec_sig.serialize_compact(); let (rec_id, data) = rec_sig.serialize_compact();
let new_rec_sig = recovery::RecoverableSignature::from_compact(&data, rec_id).unwrap(); let new_rec_sig = ecdsa::RecoverableSignature::from_compact(&data, rec_id).unwrap();
assert_eq!(rec_sig, new_rec_sig); assert_eq!(rec_sig, new_rec_sig);
let mut cbor_ser = [0u8; 100]; let mut cbor_ser = [0u8; 100];
@ -121,7 +121,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
let mut ser = Serializer::new(writer); let mut ser = Serializer::new(writer);
sig.serialize(&mut ser).unwrap(); sig.serialize(&mut ser).unwrap();
let size = ser.into_inner().bytes_written(); let size = ser.into_inner().bytes_written();
let new_sig: Signature = de::from_mut_slice(&mut cbor_ser[..size]).unwrap(); let new_sig: ecdsa::Signature = de::from_mut_slice(&mut cbor_ser[..size]).unwrap();
assert_eq!(sig, new_sig); assert_eq!(sig, new_sig);
let _ = SharedSecret::new(&public_key, &secret_key); let _ = SharedSecret::new(&public_key, &secret_key);

View File

@ -169,8 +169,8 @@ impl SharedSecret {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use rand::thread_rng; use rand::thread_rng;
use super::SharedSecret;
use super::super::Secp256k1; use super::super::Secp256k1;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -224,7 +224,7 @@ mod tests {
let x = [5u8; 32]; let x = [5u8; 32];
let y = [7u8; 32]; let y = [7u8; 32];
let mut output = [0u8; 64]; let mut output = [0u8; 64];
let res = unsafe { super::c_callback(output.as_mut_ptr(), x.as_ptr(), y.as_ptr(), ::ptr::null_mut()) }; let res = unsafe { super::c_callback(output.as_mut_ptr(), x.as_ptr(), y.as_ptr(), ptr::null_mut()) };
assert_eq!(res, 1); assert_eq!(res, 1);
let mut new_x = [0u8; 32]; let mut new_x = [0u8; 32];
let mut new_y = [0u8; 32]; let mut new_y = [0u8; 32];

502
src/ecdsa/mod.rs Normal file
View File

@ -0,0 +1,502 @@
//! Structs and functionality related to the ECDSA signature algorithm.
use core::{fmt, str, ops, ptr, mem};
use {Signing, Verification, Message, PublicKey, Secp256k1, SecretKey, from_hex, Error, ffi};
use ffi::CPtr;
#[cfg(feature = "recovery")]
mod recovery;
#[cfg(feature = "recovery")]
pub use self::recovery::{RecoveryId, RecoverableSignature};
/// An ECDSA signature
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Signature(pub(crate) ffi::Signature);
/// A DER serialized Signature
#[derive(Copy, Clone)]
pub struct SerializedSignature {
data: [u8; 72],
len: usize,
}
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let sig = self.serialize_der();
for v in sig.iter() {
write!(f, "{:02x}", v)?;
}
Ok(())
}
}
impl str::FromStr for Signature {
type Err = Error;
fn from_str(s: &str) -> Result<Signature, Error> {
let mut res = [0u8; 72];
match from_hex(s, &mut res) {
Ok(x) => Signature::from_der(&res[0..x]),
_ => Err(Error::InvalidSignature),
}
}
}
impl Default for SerializedSignature {
fn default() -> SerializedSignature {
SerializedSignature {
data: [0u8; 72],
len: 0,
}
}
}
impl PartialEq for SerializedSignature {
fn eq(&self, other: &SerializedSignature) -> bool {
self.data[..self.len] == other.data[..other.len]
}
}
impl AsRef<[u8]> for SerializedSignature {
fn as_ref(&self) -> &[u8] {
&self.data[..self.len]
}
}
impl ops::Deref for SerializedSignature {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.data[..self.len]
}
}
impl Eq for SerializedSignature {}
impl SerializedSignature {
/// Get a pointer to the underlying data with the specified capacity.
pub(crate) fn get_data_mut_ptr(&mut self) -> *mut u8 {
self.data.as_mut_ptr()
}
/// Get the capacity of the underlying data buffer.
pub fn capacity(&self) -> usize {
self.data.len()
}
/// Get the len of the used data.
pub fn len(&self) -> usize {
self.len
}
/// Set the length of the object.
pub(crate) fn set_len(&mut self, len: usize) {
self.len = len;
}
/// Convert the serialized signature into the Signature struct.
/// (This DER deserializes it)
pub fn to_signature(&self) -> Result<Signature, Error> {
Signature::from_der(&self)
}
/// Create a SerializedSignature from a Signature.
/// (this DER serializes it)
pub fn from_signature(sig: &Signature) -> SerializedSignature {
sig.serialize_der()
}
/// Check if the space is zero.
pub fn is_empty(&self) -> bool { self.len() == 0 }
}
impl Signature {
#[inline]
/// Converts a DER-encoded byte slice to a signature
pub fn from_der(data: &[u8]) -> Result<Signature, Error> {
if data.is_empty() {return Err(Error::InvalidSignature);}
unsafe {
let mut ret = ffi::Signature::new();
if ffi::secp256k1_ecdsa_signature_parse_der(
ffi::secp256k1_context_no_precomp,
&mut ret,
data.as_c_ptr(),
data.len() as usize,
) == 1
{
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
}
/// Converts a 64-byte compact-encoded byte slice to a signature
pub fn from_compact(data: &[u8]) -> Result<Signature, Error> {
if data.len() != 64 {
return Err(Error::InvalidSignature)
}
unsafe {
let mut ret = ffi::Signature::new();
if ffi::secp256k1_ecdsa_signature_parse_compact(
ffi::secp256k1_context_no_precomp,
&mut ret,
data.as_c_ptr(),
) == 1
{
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
}
/// Converts a "lax DER"-encoded byte slice to a signature. This is basically
/// only useful for validating signatures in the Bitcoin blockchain from before
/// 2016. It should never be used in new applications. This library does not
/// support serializing to this "format"
pub fn from_der_lax(data: &[u8]) -> Result<Signature, Error> {
if data.is_empty() {return Err(Error::InvalidSignature);}
unsafe {
let mut ret = ffi::Signature::new();
if ffi::ecdsa_signature_parse_der_lax(
ffi::secp256k1_context_no_precomp,
&mut ret,
data.as_c_ptr(),
data.len() as usize,
) == 1
{
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
}
/// Normalizes a signature to a "low S" form. In ECDSA, signatures are
/// of the form (r, s) where r and s are numbers lying in some finite
/// field. The verification equation will pass for (r, s) iff it passes
/// for (r, -s), so it is possible to ``modify'' signatures in transit
/// by flipping the sign of s. This does not constitute a forgery since
/// the signed message still cannot be changed, but for some applications,
/// changing even the signature itself can be a problem. Such applications
/// require a "strong signature". It is believed that ECDSA is a strong
/// signature except for this ambiguity in the sign of s, so to accommodate
/// these applications libsecp256k1 will only accept signatures for which
/// s is in the lower half of the field range. This eliminates the
/// ambiguity.
///
/// However, for some systems, signatures with high s-values are considered
/// valid. (For example, parsing the historic Bitcoin blockchain requires
/// this.) For these applications we provide this normalization function,
/// which ensures that the s value lies in the lower half of its range.
pub fn normalize_s(&mut self) {
unsafe {
// Ignore return value, which indicates whether the sig
// was already normalized. We don't care.
ffi::secp256k1_ecdsa_signature_normalize(
ffi::secp256k1_context_no_precomp,
self.as_mut_c_ptr(),
self.as_c_ptr(),
);
}
}
/// Obtains a raw pointer suitable for use with FFI functions
#[inline]
pub fn as_ptr(&self) -> *const ffi::Signature {
&self.0
}
/// Obtains a raw mutable pointer suitable for use with FFI functions
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut ffi::Signature {
&mut self.0
}
#[inline]
/// Serializes the signature in DER format
pub fn serialize_der(&self) -> SerializedSignature {
let mut ret = SerializedSignature::default();
let mut len: usize = ret.capacity();
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_der(
ffi::secp256k1_context_no_precomp,
ret.get_data_mut_ptr(),
&mut len,
self.as_c_ptr(),
);
debug_assert!(err == 1);
ret.set_len(len);
}
ret
}
#[inline]
/// Serializes the signature in compact format
pub fn serialize_compact(&self) -> [u8; 64] {
let mut ret = [0u8; 64];
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_compact(
ffi::secp256k1_context_no_precomp,
ret.as_mut_c_ptr(),
self.as_c_ptr(),
);
debug_assert!(err == 1);
}
ret
}
}
impl CPtr for Signature {
type Target = ffi::Signature;
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 signature from a FFI signature
impl From<ffi::Signature> for Signature {
#[inline]
fn from(sig: ffi::Signature) -> Signature {
Signature(sig)
}
}
#[cfg(feature = "serde")]
impl ::serde::Serialize for Signature {
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_der())
}
}
}
#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for Signature {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
if d.is_human_readable() {
d.deserialize_str(::serde_util::FromStrVisitor::new(
"a hex string representing a DER encoded Signature"
))
} else {
d.deserialize_bytes(::serde_util::BytesVisitor::new(
"raw byte stream, that represents a DER encoded Signature",
Signature::from_der
))
}
}
}
impl<C: Signing> Secp256k1<C> {
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
/// Requires a signing-capable context.
#[deprecated(since = "0.21.0", note = "Use sign_ecdsa instead.")]
pub fn sign(&self, msg: &Message, sk: &SecretKey) -> Signature {
self.sign_ecdsa(msg, sk)
}
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
/// Requires a signing-capable context.
pub fn sign_ecdsa(&self, msg: &Message, sk: &SecretKey) -> Signature {
unsafe {
let mut ret = ffi::Signature::new();
// We can assume the return value because it's not possible to construct
// an invalid signature from a valid `Message` and `SecretKey`
assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(),
sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979,
ptr::null()), 1);
Signature::from(ret)
}
}
fn sign_grind_with_check(
&self, msg: &Message,
sk: &SecretKey,
check: impl Fn(&ffi::Signature) -> bool) -> Signature {
let mut entropy_p : *const ffi::types::c_void = ptr::null();
let mut counter : u32 = 0;
let mut extra_entropy = [0u8; 32];
loop {
unsafe {
let mut ret = ffi::Signature::new();
// We can assume the return value because it's not possible to construct
// an invalid signature from a valid `Message` and `SecretKey`
assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(),
sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979,
entropy_p), 1);
if check(&ret) {
return Signature::from(ret);
}
counter += 1;
// From 1.32 can use `to_le_bytes` instead
let le_counter = counter.to_le();
let le_counter_bytes : [u8; 4] = mem::transmute(le_counter);
for (i, b) in le_counter_bytes.iter().enumerate() {
extra_entropy[i] = *b;
}
entropy_p = extra_entropy.as_ptr() as *const ffi::types::c_void;
// When fuzzing, these checks will usually spinloop forever, so just short-circuit them.
#[cfg(fuzzing)]
return Signature::from(ret);
}
}
}
/// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce
/// and "grinds" the nonce by passing extra entropy if necessary to produce
/// a signature that is less than 71 - bytes_to_grund bytes. The number
/// of signing operation performed by this function is exponential in the
/// number of bytes grinded.
/// Requires a signing capable context.
#[deprecated(since = "0.21.0", note = "Use sign_ecdsa_grind_r instead.")]
pub fn sign_grind_r(&self, msg: &Message, sk: &SecretKey, bytes_to_grind: usize) -> Signature {
self.sign_ecdsa_grind_r(msg, sk, bytes_to_grind)
}
/// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce
/// and "grinds" the nonce by passing extra entropy if necessary to produce
/// a signature that is less than 71 - bytes_to_grund bytes. The number
/// of signing operation performed by this function is exponential in the
/// number of bytes grinded.
/// Requires a signing capable context.
pub fn sign_ecdsa_grind_r(&self, msg: &Message, sk: &SecretKey, bytes_to_grind: usize) -> Signature {
let len_check = |s : &ffi::Signature| der_length_check(s, 71 - bytes_to_grind);
return self.sign_grind_with_check(msg, sk, len_check);
}
/// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce
/// and "grinds" the nonce by passing extra entropy if necessary to produce
/// a signature that is less than 71 bytes and compatible with the low r
/// signature implementation of bitcoin core. In average, this function
/// will perform two signing operations.
/// Requires a signing capable context.
#[deprecated(since = "0.21.0", note = "Use sign_ecdsa_grind_r instead.")]
pub fn sign_low_r(&self, msg: &Message, sk: &SecretKey) -> Signature {
return self.sign_grind_with_check(msg, sk, compact_sig_has_zero_first_bit)
}
/// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce
/// and "grinds" the nonce by passing extra entropy if necessary to produce
/// a signature that is less than 71 bytes and compatible with the low r
/// signature implementation of bitcoin core. In average, this function
/// will perform two signing operations.
/// Requires a signing capable context.
pub fn sign_ecdsa_low_r(&self, msg: &Message, sk: &SecretKey) -> Signature {
return self.sign_grind_with_check(msg, sk, compact_sig_has_zero_first_bit)
}
}
impl<C: Verification> Secp256k1<C> {
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
/// key `pubkey`. Returns `Ok(())` on success. Note that this function cannot
/// be used for Bitcoin consensus checking since there may exist signatures
/// which OpenSSL would verify but not libsecp256k1, or vice-versa. Requires a
/// verify-capable context.
///
/// ```rust
/// # #[cfg(feature="rand")] {
/// # use secp256k1::rand::rngs::OsRng;
/// # use secp256k1::{Secp256k1, Message, Error};
/// #
/// # let secp = Secp256k1::new();
/// # let mut rng = OsRng::new().expect("OsRng");
/// # let (secret_key, public_key) = secp.generate_keypair(&mut rng);
/// #
/// let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
/// let sig = secp.sign(&message, &secret_key);
/// assert_eq!(secp.verify(&message, &sig, &public_key), Ok(()));
///
/// let message = Message::from_slice(&[0xcd; 32]).expect("32 bytes");
/// assert_eq!(secp.verify(&message, &sig, &public_key), Err(Error::IncorrectSignature));
/// # }
/// ```
#[inline]
#[deprecated(since = "0.21.0", note = "Use verify_ecdsa instead")]
pub fn verify(&self, msg: &Message, sig: &Signature, pk: &PublicKey) -> Result<(), Error> {
self.verify_ecdsa(msg, sig, pk)
}
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
/// key `pubkey`. Returns `Ok(())` on success. Note that this function cannot
/// be used for Bitcoin consensus checking since there may exist signatures
/// which OpenSSL would verify but not libsecp256k1, or vice-versa. Requires a
/// verify-capable context.
///
/// ```rust
/// # #[cfg(feature="rand")] {
/// # use secp256k1::rand::rngs::OsRng;
/// # use secp256k1::{Secp256k1, Message, Error};
/// #
/// # let secp = Secp256k1::new();
/// # let mut rng = OsRng::new().expect("OsRng");
/// # let (secret_key, public_key) = secp.generate_keypair(&mut rng);
/// #
/// let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
/// let sig = secp.sign_ecdsa(&message, &secret_key);
/// assert_eq!(secp.verify_ecdsa(&message, &sig, &public_key), Ok(()));
///
/// let message = Message::from_slice(&[0xcd; 32]).expect("32 bytes");
/// assert_eq!(secp.verify_ecdsa(&message, &sig, &public_key), Err(Error::IncorrectSignature));
/// # }
/// ```
#[inline]
pub fn verify_ecdsa(&self, msg: &Message, sig: &Signature, pk: &PublicKey) -> Result<(), Error> {
unsafe {
if ffi::secp256k1_ecdsa_verify(self.ctx, sig.as_c_ptr(), msg.as_c_ptr(), pk.as_c_ptr()) == 0 {
Err(Error::IncorrectSignature)
} else {
Ok(())
}
}
}
}
pub(crate) fn compact_sig_has_zero_first_bit(sig: &ffi::Signature) -> bool {
let mut compact = [0u8; 64];
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_compact(
ffi::secp256k1_context_no_precomp,
compact.as_mut_c_ptr(),
sig,
);
debug_assert!(err == 1);
}
compact[0] < 0x80
}
pub(crate) fn der_length_check(sig: &ffi::Signature, max_len: usize) -> bool {
let mut ser_ret = [0u8; 72];
let mut len: usize = ser_ret.len();
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_der(
ffi::secp256k1_context_no_precomp,
ser_ret.as_mut_c_ptr(),
&mut len,
sig,
);
debug_assert!(err == 1);
}
len <= max_len
}

View File

@ -19,13 +19,11 @@
use core::ptr; use core::ptr;
use key; use key;
use super::{Secp256k1, Message, Error, Signature, Verification, Signing};
use super::ffi as super_ffi; use super::ffi as super_ffi;
pub use key::SecretKey;
pub use key::PublicKey;
use self::super_ffi::CPtr; use self::super_ffi::CPtr;
use ffi::recovery as ffi; use ffi::recovery as ffi;
use super::*;
use {Verification, Secp256k1, Signing, Message};
/// A tag used for recovering the public key from a compact signature /// A tag used for recovering the public key from a compact signature
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@ -148,9 +146,14 @@ impl From<ffi::RecoverableSignature> for RecoverableSignature {
impl<C: Signing> Secp256k1<C> { impl<C: Signing> Secp256k1<C> {
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
/// Requires a signing-capable context. /// Requires a signing-capable context.
pub fn sign_recoverable(&self, msg: &Message, sk: &key::SecretKey) #[deprecated(since = "0.21.0", note = "Use sign_ecdsa_recoverable instead.")]
-> RecoverableSignature { pub fn sign_recoverable(&self, msg: &Message, sk: &key::SecretKey) -> RecoverableSignature {
self.sign_ecdsa_recoverable(msg, sk)
}
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
/// Requires a signing-capable context.
pub fn sign_ecdsa_recoverable(&self, msg: &Message, sk: &key::SecretKey) -> RecoverableSignature {
let mut ret = ffi::RecoverableSignature::new(); let mut ret = ffi::RecoverableSignature::new();
unsafe { unsafe {
// We can assume the return value because it's not possible to construct // We can assume the return value because it's not possible to construct
@ -175,7 +178,14 @@ impl<C: Signing> Secp256k1<C> {
impl<C: Verification> Secp256k1<C> { impl<C: Verification> Secp256k1<C> {
/// Determines the public key for which `sig` is a valid signature for /// Determines the public key for which `sig` is a valid signature for
/// `msg`. Requires a verify-capable context. /// `msg`. Requires a verify-capable context.
pub fn recover(&self, msg: &Message, sig: &RecoverableSignature) #[deprecated(since = "0.21.0", note = "Use recover_ecdsa instead.")]
pub fn recover(&self, msg: &Message, sig: &RecoverableSignature) -> Result<key::PublicKey, Error> {
self.recover_ecdsa(msg, sig)
}
/// Determines the public key for which `sig` is a valid signature for
/// `msg`. Requires a verify-capable context.
pub fn recover_ecdsa(&self, msg: &Message, sig: &RecoverableSignature)
-> Result<key::PublicKey, Error> { -> Result<key::PublicKey, Error> {
unsafe { unsafe {
@ -192,12 +202,9 @@ impl<C: Verification> Secp256k1<C> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use rand::{RngCore, thread_rng}; use rand::{RngCore, thread_rng};
use key::SecretKey; use key::SecretKey;
use super::{RecoveryId, RecoverableSignature};
use super::super::{Secp256k1, Message};
use super::super::Error::{IncorrectSignature, InvalidSignature};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::wasm_bindgen_test as test; use wasm_bindgen_test::wasm_bindgen_test as test;
@ -275,7 +282,7 @@ mod tests {
let mut msg = [0u8; 32]; let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg); thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
assert_eq!(s.verify(&msg, &sig, &pk), Err(IncorrectSignature)); assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Err(Error::IncorrectSignature));
let recovered_key = s.recover(&msg, &sigr).unwrap(); let recovered_key = s.recover(&msg, &sigr).unwrap();
assert!(recovered_key != pk); assert!(recovered_key != pk);
@ -306,7 +313,7 @@ mod tests {
// Zero is not a valid sig // Zero is not a valid sig
let sig = RecoverableSignature::from_compact(&[0; 64], RecoveryId(0)).unwrap(); let sig = RecoverableSignature::from_compact(&[0; 64], RecoveryId(0)).unwrap();
assert_eq!(s.recover(&msg, &sig), Err(InvalidSignature)); assert_eq!(s.recover(&msg, &sig), Err(Error::InvalidSignature));
// ...but 111..111 is // ...but 111..111 is
let sig = RecoverableSignature::from_compact(&[1; 64], RecoveryId(0)).unwrap(); let sig = RecoverableSignature::from_compact(&[1; 64], RecoveryId(0)).unwrap();
assert!(s.recover(&msg, &sig).is_ok()); assert!(s.recover(&msg, &sig).is_ok());

View File

@ -17,7 +17,7 @@
#[cfg(any(test, feature = "rand"))] use rand::Rng; #[cfg(any(test, feature = "rand"))] use rand::Rng;
use core::{fmt, str}; use core::{fmt, ptr, str};
use super::{from_hex, Secp256k1}; use super::{from_hex, Secp256k1};
use super::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey}; use super::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey};
@ -134,9 +134,9 @@ impl SecretKey {
} }
} }
/// Creates a new secret key using data from BIP-340 [`::schnorrsig::KeyPair`] /// Creates a new secret key using data from BIP-340 [`KeyPair`]
#[inline] #[inline]
pub fn from_keypair(keypair: &::schnorrsig::KeyPair) -> Self { pub fn from_keypair(keypair: &KeyPair) -> Self {
let mut sk = [0u8; constants::SECRET_KEY_SIZE]; let mut sk = [0u8; constants::SECRET_KEY_SIZE];
unsafe { unsafe {
let ret = ffi::secp256k1_keypair_sec( let ret = ffi::secp256k1_keypair_sec(
@ -297,9 +297,9 @@ impl PublicKey {
} }
} }
/// Creates a new compressed public key key using data from BIP-340 [`::schnorrsig::KeyPair`] /// Creates a new compressed public key using data from BIP-340 [`KeyPair`].
#[inline] #[inline]
pub fn from_keypair(keypair: &::schnorrsig::KeyPair) -> Self { pub fn from_keypair(keypair: &KeyPair) -> Self {
unsafe { unsafe {
let mut pk = ffi::PublicKey::new(); let mut pk = ffi::PublicKey::new();
let ret = ffi::secp256k1_keypair_pub( let ret = ffi::secp256k1_keypair_pub(
@ -505,6 +505,420 @@ impl Ord for PublicKey {
} }
} }
/// Opaque data structure that holds a keypair consisting of a secret and a public key.
#[derive(Clone)]
pub struct KeyPair(ffi::KeyPair);
impl_display_secret!(KeyPair);
impl KeyPair {
/// Obtains a raw const pointer suitable for use with FFI functions
#[inline]
pub fn as_ptr(&self) -> *const ffi::KeyPair {
&self.0
}
/// Obtains a raw mutable pointer suitable for use with FFI functions
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut ffi::KeyPair {
&mut self.0
}
/// Creates a Schnorr KeyPair directly from generic Secp256k1 secret key
///
/// # Panic
///
/// Panics if internal representation of the provided [`SecretKey`] does not hold correct secret
/// key value obtained from Secp256k1 library previously, specifically when secret key value is
/// out-of-range (0 or in excess of the group order).
#[inline]
pub fn from_secret_key<C: Signing>(
secp: &Secp256k1<C>,
sk: SecretKey,
) -> KeyPair {
unsafe {
let mut kp = ffi::KeyPair::new();
if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, sk.as_c_ptr()) == 1 {
KeyPair(kp)
} else {
panic!("the provided secret key is invalid: it is corrupted or was not produced by Secp256k1 library")
}
}
}
/// Creates a Schnorr KeyPair directly from a secret key slice.
///
/// # Errors
///
/// [`Error::InvalidSecretKey`] if the provided data has an incorrect length, exceeds Secp256k1
/// field `p` value or the corresponding public key is not even.
#[inline]
pub fn from_seckey_slice<C: Signing>(
secp: &Secp256k1<C>,
data: &[u8],
) -> Result<KeyPair, Error> {
if data.is_empty() || data.len() != constants::SECRET_KEY_SIZE {
return Err(Error::InvalidSecretKey);
}
unsafe {
let mut kp = ffi::KeyPair::new();
if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, data.as_c_ptr()) == 1 {
Ok(KeyPair(kp))
} else {
Err(Error::InvalidSecretKey)
}
}
}
/// Creates a Schnorr KeyPair directly from a secret key string
///
/// # Errors
///
/// [`Error::InvalidSecretKey`] if corresponding public key for the provided secret key is not even.
#[inline]
pub fn from_seckey_str<C: Signing>(secp: &Secp256k1<C>, s: &str) -> Result<KeyPair, Error> {
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])
}
_ => Err(Error::InvalidPublicKey),
}
}
/// Creates a new random secret key. Requires compilation with the "rand" feature.
#[inline]
#[cfg(any(test, feature = "rand"))]
pub fn new<R: ::rand::Rng + ?Sized, C: Signing>(secp: &Secp256k1<C>, rng: &mut R) -> KeyPair {
let mut random_32_bytes = || {
let mut ret = [0u8; 32];
rng.fill_bytes(&mut ret);
ret
};
let mut data = random_32_bytes();
unsafe {
let mut keypair = ffi::KeyPair::new();
while ffi::secp256k1_keypair_create(secp.ctx, &mut keypair, data.as_c_ptr()) == 0 {
data = random_32_bytes();
}
KeyPair(keypair)
}
}
/// Serialize the key pair as a secret key byte value
#[inline]
pub fn serialize_secret(&self) -> [u8; constants::SECRET_KEY_SIZE] {
*SecretKey::from_keypair(self).as_ref()
}
/// Tweak a keypair by adding the given tweak to the secret key and updating the public key
/// accordingly.
///
/// Will return an error if the resulting key would be invalid or if the tweak was not a 32-byte
/// length slice.
///
/// NB: Will not error if the tweaked public key has an odd value and can't be used for
/// BIP 340-342 purposes.
// TODO: Add checked implementation
#[inline]
pub fn tweak_add_assign<C: Verification>(
&mut self,
secp: &Secp256k1<C>,
tweak: &[u8],
) -> Result<(), Error> {
if tweak.len() != 32 {
return Err(Error::InvalidTweak);
}
unsafe {
let err = ffi::secp256k1_keypair_xonly_tweak_add(
secp.ctx,
&mut self.0,
tweak.as_c_ptr(),
);
if err == 1 {
Ok(())
} else {
Err(Error::InvalidTweak)
}
}
}
}
impl From<KeyPair> for SecretKey {
#[inline]
fn from(pair: KeyPair) -> Self {
SecretKey::from_keypair(&pair)
}
}
impl<'a> From<&'a KeyPair> for SecretKey {
#[inline]
fn from(pair: &'a KeyPair) -> Self {
SecretKey::from_keypair(pair)
}
}
impl From<KeyPair> for PublicKey {
#[inline]
fn from(pair: KeyPair) -> Self {
PublicKey::from_keypair(&pair)
}
}
impl<'a> From<&'a KeyPair> for PublicKey {
#[inline]
fn from(pair: &'a KeyPair) -> Self {
PublicKey::from_keypair(pair)
}
}
/// 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)] #[cfg(test)]
mod test { mod test {
use Secp256k1; use Secp256k1;

View File

@ -47,8 +47,8 @@
//! let (secret_key, public_key) = secp.generate_keypair(&mut rng); //! let (secret_key, public_key) = secp.generate_keypair(&mut rng);
//! let message = Message::from_hashed_data::<sha256::Hash>("Hello World!".as_bytes()); //! let message = Message::from_hashed_data::<sha256::Hash>("Hello World!".as_bytes());
//! //!
//! let sig = secp.sign(&message, &secret_key); //! let sig = secp.sign_ecdsa(&message, &secret_key);
//! assert!(secp.verify(&message, &sig, &public_key).is_ok()); //! assert!(secp.verify_ecdsa(&message, &sig, &public_key).is_ok());
//! # } //! # }
//! ``` //! ```
//! //!
@ -66,14 +66,14 @@
//! // See the above example for how to use this library together with bitcoin_hashes. //! // See the above example for how to use this library together with bitcoin_hashes.
//! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); //! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
//! //!
//! let sig = secp.sign(&message, &secret_key); //! let sig = secp.sign_ecdsa(&message, &secret_key);
//! assert!(secp.verify(&message, &sig, &public_key).is_ok()); //! assert!(secp.verify_ecdsa(&message, &sig, &public_key).is_ok());
//! ``` //! ```
//! //!
//! Users who only want to verify signatures can use a cheaper context, like so: //! Users who only want to verify signatures can use a cheaper context, like so:
//! //!
//! ```rust //! ```rust
//! use secp256k1::{Secp256k1, Message, Signature, PublicKey}; //! use secp256k1::{Secp256k1, Message, ecdsa, PublicKey};
//! //!
//! let secp = Secp256k1::verification_only(); //! let secp = Secp256k1::verification_only();
//! //!
@ -92,7 +92,7 @@
//! 0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50, //! 0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50,
//! ]).expect("messages must be 32 bytes and are expected to be hashes"); //! ]).expect("messages must be 32 bytes and are expected to be hashes");
//! //!
//! let sig = Signature::from_compact(&[ //! let sig = ecdsa::Signature::from_compact(&[
//! 0xdc, 0x4d, 0xc2, 0x64, 0xa9, 0xfe, 0xf1, 0x7a, //! 0xdc, 0x4d, 0xc2, 0x64, 0xa9, 0xfe, 0xf1, 0x7a,
//! 0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a, //! 0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a,
//! 0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94, //! 0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94,
@ -104,7 +104,7 @@
//! ]).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes"); //! ]).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes");
//! //!
//! # #[cfg(not(fuzzing))] //! # #[cfg(not(fuzzing))]
//! assert!(secp.verify(&message, &sig, &public_key).is_ok()); //! assert!(secp.verify_ecdsa(&message, &sig, &public_key).is_ok());
//! ``` //! ```
//! //!
//! Observe that the same code using, say [`signing_only`](struct.Secp256k1.html#method.signing_only) //! Observe that the same code using, say [`signing_only`](struct.Secp256k1.html#method.signing_only)
@ -143,21 +143,23 @@ mod macros;
#[macro_use] #[macro_use]
mod secret; mod secret;
mod context; mod context;
mod key;
pub mod constants; pub mod constants;
pub mod ecdh; pub mod ecdh;
pub mod key; pub mod ecdsa;
pub mod schnorrsig; pub mod schnorr;
#[cfg(feature = "recovery")]
pub mod recovery;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
mod serde_util; mod serde_util;
pub use key::SecretKey; pub use key::SecretKey;
pub use key::PublicKey; pub use key::PublicKey;
pub use key::ONE_KEY;
pub use key::KeyPair;
pub use key::XOnlyPublicKey;
pub use context::*; pub use context::*;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::ops::Deref; use core::{mem, fmt, str};
use core::{mem, fmt, ptr, str};
use ffi::{CPtr, types::AlignedType}; use ffi::{CPtr, types::AlignedType};
#[cfg(feature = "global-context-less-secure")] #[cfg(feature = "global-context-less-secure")]
@ -166,44 +168,6 @@ pub use context::global::SECP256K1;
#[cfg(feature = "bitcoin_hashes")] #[cfg(feature = "bitcoin_hashes")]
use hashes::Hash; use hashes::Hash;
/// An ECDSA signature
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Signature(ffi::Signature);
/// A DER serialized Signature
#[derive(Copy, Clone)]
pub struct SerializedSignature {
data: [u8; 72],
len: usize,
}
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let sig = self.serialize_der();
for v in sig.iter() {
write!(f, "{:02x}", v)?;
}
Ok(())
}
}
impl str::FromStr for Signature {
type Err = Error;
fn from_str(s: &str) -> Result<Signature, Error> {
let mut res = [0u8; 72];
match from_hex(s, &mut res) {
Ok(x) => Signature::from_der(&res[0..x]),
_ => Err(Error::InvalidSignature),
}
}
}
/// Trait describing something that promises to be a 32-byte random number; in particular, /// Trait describing something that promises to be a 32-byte random number; in particular,
/// it has negligible probability of being zero or overflowing the group order. Such objects /// it has negligible probability of being zero or overflowing the group order. Such objects
/// may be converted to `Message`s without any error paths. /// may be converted to `Message`s without any error paths.
@ -233,231 +197,6 @@ impl<T: hashes::sha256t::Tag> ThirtyTwoByteHash for hashes::sha256t::Hash<T> {
} }
} }
impl SerializedSignature {
/// Get a pointer to the underlying data with the specified capacity.
pub(crate) fn get_data_mut_ptr(&mut self) -> *mut u8 {
self.data.as_mut_ptr()
}
/// Get the capacity of the underlying data buffer.
pub fn capacity(&self) -> usize {
self.data.len()
}
/// Get the len of the used data.
pub fn len(&self) -> usize {
self.len
}
/// Set the length of the object.
pub(crate) fn set_len(&mut self, len: usize) {
self.len = len;
}
/// Convert the serialized signature into the Signature struct.
/// (This DER deserializes it)
pub fn to_signature(&self) -> Result<Signature, Error> {
Signature::from_der(&self)
}
/// Create a SerializedSignature from a Signature.
/// (this DER serializes it)
pub fn from_signature(sig: &Signature) -> SerializedSignature {
sig.serialize_der()
}
/// Check if the space is zero.
pub fn is_empty(&self) -> bool { self.len() == 0 }
}
impl Signature {
#[inline]
/// Converts a DER-encoded byte slice to a signature
pub fn from_der(data: &[u8]) -> Result<Signature, Error> {
if data.is_empty() {return Err(Error::InvalidSignature);}
unsafe {
let mut ret = ffi::Signature::new();
if ffi::secp256k1_ecdsa_signature_parse_der(
ffi::secp256k1_context_no_precomp,
&mut ret,
data.as_c_ptr(),
data.len() as usize,
) == 1
{
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
}
/// Converts a 64-byte compact-encoded byte slice to a signature
pub fn from_compact(data: &[u8]) -> Result<Signature, Error> {
if data.len() != 64 {
return Err(Error::InvalidSignature)
}
unsafe {
let mut ret = ffi::Signature::new();
if ffi::secp256k1_ecdsa_signature_parse_compact(
ffi::secp256k1_context_no_precomp,
&mut ret,
data.as_c_ptr(),
) == 1
{
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
}
/// Converts a "lax DER"-encoded byte slice to a signature. This is basically
/// only useful for validating signatures in the Bitcoin blockchain from before
/// 2016. It should never be used in new applications. This library does not
/// support serializing to this "format"
pub fn from_der_lax(data: &[u8]) -> Result<Signature, Error> {
if data.is_empty() {return Err(Error::InvalidSignature);}
unsafe {
let mut ret = ffi::Signature::new();
if ffi::ecdsa_signature_parse_der_lax(
ffi::secp256k1_context_no_precomp,
&mut ret,
data.as_c_ptr(),
data.len() as usize,
) == 1
{
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
}
/// Normalizes a signature to a "low S" form. In ECDSA, signatures are
/// of the form (r, s) where r and s are numbers lying in some finite
/// field. The verification equation will pass for (r, s) iff it passes
/// for (r, -s), so it is possible to ``modify'' signatures in transit
/// by flipping the sign of s. This does not constitute a forgery since
/// the signed message still cannot be changed, but for some applications,
/// changing even the signature itself can be a problem. Such applications
/// require a "strong signature". It is believed that ECDSA is a strong
/// signature except for this ambiguity in the sign of s, so to accommodate
/// these applications libsecp256k1 will only accept signatures for which
/// s is in the lower half of the field range. This eliminates the
/// ambiguity.
///
/// However, for some systems, signatures with high s-values are considered
/// valid. (For example, parsing the historic Bitcoin blockchain requires
/// this.) For these applications we provide this normalization function,
/// which ensures that the s value lies in the lower half of its range.
pub fn normalize_s(&mut self) {
unsafe {
// Ignore return value, which indicates whether the sig
// was already normalized. We don't care.
ffi::secp256k1_ecdsa_signature_normalize(
ffi::secp256k1_context_no_precomp,
self.as_mut_c_ptr(),
self.as_c_ptr(),
);
}
}
/// Obtains a raw pointer suitable for use with FFI functions
#[inline]
pub fn as_ptr(&self) -> *const ffi::Signature {
&self.0
}
/// Obtains a raw mutable pointer suitable for use with FFI functions
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut ffi::Signature {
&mut self.0
}
#[inline]
/// Serializes the signature in DER format
pub fn serialize_der(&self) -> SerializedSignature {
let mut ret = SerializedSignature::default();
let mut len: usize = ret.capacity();
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_der(
ffi::secp256k1_context_no_precomp,
ret.get_data_mut_ptr(),
&mut len,
self.as_c_ptr(),
);
debug_assert!(err == 1);
ret.set_len(len);
}
ret
}
#[inline]
/// Serializes the signature in compact format
pub fn serialize_compact(&self) -> [u8; 64] {
let mut ret = [0u8; 64];
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_compact(
ffi::secp256k1_context_no_precomp,
ret.as_mut_c_ptr(),
self.as_c_ptr(),
);
debug_assert!(err == 1);
}
ret
}
}
impl CPtr for Signature {
type Target = ffi::Signature;
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 signature from a FFI signature
impl From<ffi::Signature> for Signature {
#[inline]
fn from(sig: ffi::Signature) -> Signature {
Signature(sig)
}
}
#[cfg(feature = "serde")]
impl ::serde::Serialize for Signature {
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_der())
}
}
}
#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for Signature {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
if d.is_human_readable() {
d.deserialize_str(serde_util::FromStrVisitor::new(
"a hex string representing a DER encoded Signature"
))
} else {
d.deserialize_bytes(serde_util::BytesVisitor::new(
"raw byte stream, that represents a DER encoded Signature",
Signature::from_der
))
}
}
}
/// A (hashed) message input to an ECDSA signature /// A (hashed) message input to an ECDSA signature
pub struct Message([u8; constants::MESSAGE_SIZE]); pub struct Message([u8; constants::MESSAGE_SIZE]);
impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE); impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE);
@ -573,41 +312,10 @@ unsafe impl<C: Context> Send for Secp256k1<C> {}
// The API does not permit any mutation of `Secp256k1` objects except through `&mut` references // The API does not permit any mutation of `Secp256k1` objects except through `&mut` references
unsafe impl<C: Context> Sync for Secp256k1<C> {} unsafe impl<C: Context> Sync for Secp256k1<C> {}
impl<C: Context> PartialEq for Secp256k1<C> { impl<C: Context> PartialEq for Secp256k1<C> {
fn eq(&self, _other: &Secp256k1<C>) -> bool { true } fn eq(&self, _other: &Secp256k1<C>) -> bool { true }
} }
impl Default for SerializedSignature {
fn default() -> SerializedSignature {
SerializedSignature {
data: [0u8; 72],
len: 0,
}
}
}
impl PartialEq for SerializedSignature {
fn eq(&self, other: &SerializedSignature) -> bool {
self.data[..self.len] == other.data[..other.len]
}
}
impl AsRef<[u8]> for SerializedSignature {
fn as_ref(&self) -> &[u8] {
&self.data[..self.len]
}
}
impl Deref for SerializedSignature {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.data[..self.len]
}
}
impl Eq for SerializedSignature {}
impl<C: Context> Eq for Secp256k1<C> { } impl<C: Context> Eq for Secp256k1<C> { }
impl<C: Context> Drop for Secp256k1<C> { impl<C: Context> Drop for Secp256k1<C> {
@ -672,109 +380,7 @@ impl<C: Context> Secp256k1<C> {
} }
} }
fn der_length_check(sig: &ffi::Signature, max_len: usize) -> bool {
let mut ser_ret = [0u8; 72];
let mut len: usize = ser_ret.len();
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_der(
ffi::secp256k1_context_no_precomp,
ser_ret.as_mut_c_ptr(),
&mut len,
sig,
);
debug_assert!(err == 1);
}
len <= max_len
}
fn compact_sig_has_zero_first_bit(sig: &ffi::Signature) -> bool {
let mut compact = [0u8; 64];
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_compact(
ffi::secp256k1_context_no_precomp,
compact.as_mut_c_ptr(),
sig,
);
debug_assert!(err == 1);
}
compact[0] < 0x80
}
impl<C: Signing> Secp256k1<C> { impl<C: Signing> Secp256k1<C> {
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
/// Requires a signing-capable context.
pub fn sign(&self, msg: &Message, sk: &key::SecretKey)
-> Signature {
unsafe {
let mut ret = ffi::Signature::new();
// We can assume the return value because it's not possible to construct
// an invalid signature from a valid `Message` and `SecretKey`
assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(),
sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979,
ptr::null()), 1);
Signature::from(ret)
}
}
fn sign_grind_with_check(
&self, msg: &Message,
sk: &key::SecretKey,
check: impl Fn(&ffi::Signature) -> bool) -> Signature {
let mut entropy_p : *const ffi::types::c_void = ptr::null();
let mut counter : u32 = 0;
let mut extra_entropy = [0u8; 32];
loop {
unsafe {
let mut ret = ffi::Signature::new();
// We can assume the return value because it's not possible to construct
// an invalid signature from a valid `Message` and `SecretKey`
assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(),
sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979,
entropy_p), 1);
if check(&ret) {
return Signature::from(ret);
}
counter += 1;
// From 1.32 can use `to_le_bytes` instead
let le_counter = counter.to_le();
let le_counter_bytes : [u8; 4] = mem::transmute(le_counter);
for (i, b) in le_counter_bytes.iter().enumerate() {
extra_entropy[i] = *b;
}
entropy_p = extra_entropy.as_ptr() as *const ffi::types::c_void;
// When fuzzing, these checks will usually spinloop forever, so just short-circuit them.
#[cfg(fuzzing)]
return Signature::from(ret);
}
}
}
/// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce
/// and "grinds" the nonce by passing extra entropy if necessary to produce
/// a signature that is less than 71 - bytes_to_grund bytes. The number
/// of signing operation performed by this function is exponential in the
/// number of bytes grinded.
/// Requires a signing capable context.
pub fn sign_grind_r(&self, msg: &Message, sk: &key::SecretKey, bytes_to_grind: usize) -> Signature {
let len_check = |s : &ffi::Signature| der_length_check(s, 71 - bytes_to_grind);
return self.sign_grind_with_check(msg, sk, len_check);
}
/// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce
/// and "grinds" the nonce by passing extra entropy if necessary to produce
/// a signature that is less than 71 bytes and compatible with the low r
/// signature implementation of bitcoin core. In average, this function
/// will perform two signing operations.
/// Requires a signing capable context.
pub fn sign_low_r(&self, msg: &Message, sk: &key::SecretKey) -> Signature {
return self.sign_grind_with_check(msg, sk, compact_sig_has_zero_first_bit)
}
/// Generates a random keypair. Convenience function for `key::SecretKey::new` /// Generates a random keypair. Convenience function for `key::SecretKey::new`
/// and `key::PublicKey::from_secret_key`; call those functions directly for /// and `key::PublicKey::from_secret_key`; call those functions directly for
/// batch key generation. Requires a signing-capable context. Requires compilation /// batch key generation. Requires a signing-capable context. Requires compilation
@ -789,42 +395,6 @@ impl<C: Signing> Secp256k1<C> {
} }
} }
impl<C: Verification> Secp256k1<C> {
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
/// key `pubkey`. Returns `Ok(())` on success. Note that this function cannot
/// be used for Bitcoin consensus checking since there may exist signatures
/// which OpenSSL would verify but not libsecp256k1, or vice-versa. Requires a
/// verify-capable context.
///
/// ```rust
/// # #[cfg(feature="rand")] {
/// # use secp256k1::rand::rngs::OsRng;
/// # use secp256k1::{Secp256k1, Message, Error};
/// #
/// # let secp = Secp256k1::new();
/// # let mut rng = OsRng::new().expect("OsRng");
/// # let (secret_key, public_key) = secp.generate_keypair(&mut rng);
/// #
/// let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
/// let sig = secp.sign(&message, &secret_key);
/// assert_eq!(secp.verify(&message, &sig, &public_key), Ok(()));
///
/// let message = Message::from_slice(&[0xcd; 32]).expect("32 bytes");
/// assert_eq!(secp.verify(&message, &sig, &public_key), Err(Error::IncorrectSignature));
/// # }
/// ```
#[inline]
pub fn verify(&self, msg: &Message, sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> {
unsafe {
if ffi::secp256k1_ecdsa_verify(self.ctx, sig.as_c_ptr(), msg.as_c_ptr(), pk.as_c_ptr()) == 0 {
Err(Error::IncorrectSignature)
} else {
Ok(())
}
}
}
}
/// Utility function used to parse hex into a target u8 buffer. Returns /// Utility function used to parse hex into a target u8 buffer. Returns
/// the number of bytes converted or an error if it encounters an invalid /// the number of bytes converted or an error if it encounters an invalid
/// character or unexpected end of string. /// character or unexpected end of string.
@ -877,17 +447,11 @@ fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ()> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use rand::{RngCore, thread_rng}; use rand::{RngCore, thread_rng};
use std::str::FromStr; use std::str::FromStr;
use std::marker::PhantomData; use std::marker::PhantomData;
use ffi::types::AlignedType;
use key::{SecretKey, PublicKey};
use super::{from_hex, to_hex};
use super::constants;
use super::{Secp256k1, Signature, Message};
use super::Error::{InvalidMessage, IncorrectSignature, InvalidSignature};
use ffi::{self, types::AlignedType};
use context::*;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::wasm_bindgen_test as test; use wasm_bindgen_test::wasm_bindgen_test as test;
@ -915,12 +479,12 @@ mod tests {
let (sk, pk) = full.generate_keypair(&mut thread_rng()); let (sk, pk) = full.generate_keypair(&mut thread_rng());
let msg = Message::from_slice(&[2u8; 32]).unwrap(); let msg = Message::from_slice(&[2u8; 32]).unwrap();
// Try signing // Try signing
assert_eq!(sign.sign(&msg, &sk), full.sign(&msg, &sk)); assert_eq!(sign.sign_ecdsa(&msg, &sk), full.sign_ecdsa(&msg, &sk));
let sig = full.sign(&msg, &sk); let sig = full.sign_ecdsa(&msg, &sk);
// Try verifying // Try verifying
assert!(vrfy.verify(&msg, &sig, &pk).is_ok()); assert!(vrfy.verify_ecdsa(&msg, &sig, &pk).is_ok());
assert!(full.verify(&msg, &sig, &pk).is_ok()); assert!(full.verify_ecdsa(&msg, &sig, &pk).is_ok());
drop(full);drop(sign);drop(vrfy); drop(full);drop(sign);drop(vrfy);
@ -944,12 +508,12 @@ mod tests {
let (sk, pk) = full.generate_keypair(&mut thread_rng()); let (sk, pk) = full.generate_keypair(&mut thread_rng());
let msg = Message::from_slice(&[2u8; 32]).unwrap(); let msg = Message::from_slice(&[2u8; 32]).unwrap();
// Try signing // Try signing
assert_eq!(sign.sign(&msg, &sk), full.sign(&msg, &sk)); assert_eq!(sign.sign_ecdsa(&msg, &sk), full.sign_ecdsa(&msg, &sk));
let sig = full.sign(&msg, &sk); let sig = full.sign_ecdsa(&msg, &sk);
// Try verifying // Try verifying
assert!(vrfy.verify(&msg, &sig, &pk).is_ok()); assert!(vrfy.verify_ecdsa(&msg, &sig, &pk).is_ok());
assert!(full.verify(&msg, &sig, &pk).is_ok()); assert!(full.verify_ecdsa(&msg, &sig, &pk).is_ok());
unsafe { unsafe {
ManuallyDrop::drop(&mut full); ManuallyDrop::drop(&mut full);
@ -988,12 +552,12 @@ mod tests {
let (sk, pk) = full.generate_keypair(&mut thread_rng()); let (sk, pk) = full.generate_keypair(&mut thread_rng());
let msg = Message::from_slice(&[2u8; 32]).unwrap(); let msg = Message::from_slice(&[2u8; 32]).unwrap();
// Try signing // Try signing
assert_eq!(sign.sign(&msg, &sk), full.sign(&msg, &sk)); assert_eq!(sign.sign_ecdsa(&msg, &sk), full.sign_ecdsa(&msg, &sk));
let sig = full.sign(&msg, &sk); let sig = full.sign_ecdsa(&msg, &sk);
// Try verifying // Try verifying
assert!(vrfy.verify(&msg, &sig, &pk).is_ok()); assert!(vrfy.verify_ecdsa(&msg, &sig, &pk).is_ok());
assert!(full.verify(&msg, &sig, &pk).is_ok()); assert!(full.verify_ecdsa(&msg, &sig, &pk).is_ok());
} }
#[test] #[test]
@ -1010,12 +574,12 @@ mod tests {
let (sk, pk) = full.generate_keypair(&mut thread_rng()); let (sk, pk) = full.generate_keypair(&mut thread_rng());
// Try signing // Try signing
assert_eq!(sign.sign(&msg, &sk), full.sign(&msg, &sk)); assert_eq!(sign.sign_ecdsa(&msg, &sk), full.sign_ecdsa(&msg, &sk));
let sig = full.sign(&msg, &sk); let sig = full.sign_ecdsa(&msg, &sk);
// Try verifying // Try verifying
assert!(vrfy.verify(&msg, &sig, &pk).is_ok()); assert!(vrfy.verify_ecdsa(&msg, &sig, &pk).is_ok());
assert!(full.verify(&msg, &sig, &pk).is_ok()); assert!(full.verify_ecdsa(&msg, &sig, &pk).is_ok());
// Check that we can produce keys from slices with no precomputation // Check that we can produce keys from slices with no precomputation
let (pk_slice, sk_slice) = (&pk.serialize(), &sk[..]); let (pk_slice, sk_slice) = (&pk.serialize(), &sk[..]);
@ -1036,19 +600,19 @@ mod tests {
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
let (sk, _) = s.generate_keypair(&mut thread_rng()); let (sk, _) = s.generate_keypair(&mut thread_rng());
let sig1 = s.sign(&msg, &sk); let sig1 = s.sign_ecdsa(&msg, &sk);
let der = sig1.serialize_der(); let der = sig1.serialize_der();
let sig2 = Signature::from_der(&der[..]).unwrap(); let sig2 = ecdsa::Signature::from_der(&der[..]).unwrap();
assert_eq!(sig1, sig2); assert_eq!(sig1, sig2);
let compact = sig1.serialize_compact(); let compact = sig1.serialize_compact();
let sig2 = Signature::from_compact(&compact[..]).unwrap(); let sig2 = ecdsa::Signature::from_compact(&compact[..]).unwrap();
assert_eq!(sig1, sig2); assert_eq!(sig1, sig2);
assert!(Signature::from_compact(&der[..]).is_err()); assert!(ecdsa::Signature::from_compact(&der[..]).is_err());
assert!(Signature::from_compact(&compact[0..4]).is_err()); assert!(ecdsa::Signature::from_compact(&compact[0..4]).is_err());
assert!(Signature::from_der(&compact[..]).is_err()); assert!(ecdsa::Signature::from_der(&compact[..]).is_err());
assert!(Signature::from_der(&der[0..4]).is_err()); assert!(ecdsa::Signature::from_der(&der[0..4]).is_err());
} }
} }
@ -1058,27 +622,27 @@ mod tests {
let byte_str = hex!(hex_str); let byte_str = hex!(hex_str);
assert_eq!( assert_eq!(
Signature::from_der(&byte_str).expect("byte str decode"), ecdsa::Signature::from_der(&byte_str).expect("byte str decode"),
Signature::from_str(&hex_str).expect("byte str decode") ecdsa::Signature::from_str(&hex_str).expect("byte str decode")
); );
let sig = Signature::from_str(&hex_str).expect("byte str decode"); let sig = ecdsa::Signature::from_str(&hex_str).expect("byte str decode");
assert_eq!(&sig.to_string(), hex_str); assert_eq!(&sig.to_string(), hex_str);
assert_eq!(&format!("{:?}", sig), hex_str); assert_eq!(&format!("{:?}", sig), hex_str);
assert!(Signature::from_str( assert!(ecdsa::Signature::from_str(
"3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\ "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\
72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab4" 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab4"
).is_err()); ).is_err());
assert!(Signature::from_str( assert!(ecdsa::Signature::from_str(
"3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\ "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\
72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab" 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab"
).is_err()); ).is_err());
assert!(Signature::from_str( assert!(ecdsa::Signature::from_str(
"3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\ "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\
72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eabxx" 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eabxx"
).is_err()); ).is_err());
assert!(Signature::from_str( assert!(ecdsa::Signature::from_str(
"3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\ "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\
72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\ 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\
72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\ 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\
@ -1089,7 +653,7 @@ mod tests {
// 71 byte signature // 71 byte signature
let hex_str = "30450221009d0bad576719d32ae76bedb34c774866673cbde3f4e12951555c9408e6ce774b02202876e7102f204f6bfee26c967c3926ce702cf97d4b010062e193f763190f6776"; let hex_str = "30450221009d0bad576719d32ae76bedb34c774866673cbde3f4e12951555c9408e6ce774b02202876e7102f204f6bfee26c967c3926ce702cf97d4b010062e193f763190f6776";
let sig = Signature::from_str(&hex_str).expect("byte str decode"); let sig = ecdsa::Signature::from_str(&hex_str).expect("byte str decode");
assert_eq!(&format!("{}", sig), hex_str); assert_eq!(&format!("{}", sig), hex_str);
} }
@ -1098,7 +662,7 @@ mod tests {
macro_rules! check_lax_sig( macro_rules! check_lax_sig(
($hex:expr) => ({ ($hex:expr) => ({
let sig = hex!($hex); let sig = hex!($hex);
assert!(Signature::from_der_lax(&sig[..]).is_ok()); assert!(ecdsa::Signature::from_der_lax(&sig[..]).is_ok());
}) })
); );
@ -1112,7 +676,7 @@ mod tests {
} }
#[test] #[test]
fn sign_and_verify() { fn sign_and_verify_ecdsa() {
let mut s = Secp256k1::new(); let mut s = Secp256k1::new();
s.randomize(&mut thread_rng()); s.randomize(&mut thread_rng());
@ -1122,12 +686,12 @@ mod tests {
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng()); let (sk, pk) = s.generate_keypair(&mut thread_rng());
let sig = s.sign(&msg, &sk); let sig = s.sign_ecdsa(&msg, &sk);
assert_eq!(s.verify(&msg, &sig, &pk), Ok(())); assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Ok(()));
let low_r_sig = s.sign_low_r(&msg, &sk); let low_r_sig = s.sign_ecdsa_low_r(&msg, &sk);
assert_eq!(s.verify(&msg, &low_r_sig, &pk), Ok(())); assert_eq!(s.verify_ecdsa(&msg, &low_r_sig, &pk), Ok(()));
let grind_r_sig = s.sign_grind_r(&msg, &sk, 1); let grind_r_sig = s.sign_ecdsa_grind_r(&msg, &sk, 1);
assert_eq!(s.verify(&msg, &grind_r_sig, &pk), Ok(())); assert_eq!(s.verify_ecdsa(&msg, &grind_r_sig, &pk), Ok(()));
let compact = sig.serialize_compact(); let compact = sig.serialize_compact();
if compact[0] < 0x80 { if compact[0] < 0x80 {
assert_eq!(sig, low_r_sig); assert_eq!(sig, low_r_sig);
@ -1136,9 +700,9 @@ mod tests {
assert_ne!(sig, low_r_sig); assert_ne!(sig, low_r_sig);
} }
#[cfg(not(fuzzing))] // mocked sig generation doesn't produce low-R sigs #[cfg(not(fuzzing))] // mocked sig generation doesn't produce low-R sigs
assert!(super::compact_sig_has_zero_first_bit(&low_r_sig.0)); assert!(ecdsa::compact_sig_has_zero_first_bit(&low_r_sig.0));
#[cfg(not(fuzzing))] // mocked sig generation doesn't produce low-R sigs #[cfg(not(fuzzing))] // mocked sig generation doesn't produce low-R sigs
assert!(super::der_length_check(&grind_r_sig.0, 70)); assert!(ecdsa::der_length_check(&grind_r_sig.0, 70));
} }
} }
@ -1164,13 +728,13 @@ mod tests {
for key in wild_keys.iter().map(|k| SecretKey::from_slice(&k[..]).unwrap()) { for key in wild_keys.iter().map(|k| SecretKey::from_slice(&k[..]).unwrap()) {
for msg in wild_msgs.iter().map(|m| Message::from_slice(&m[..]).unwrap()) { for msg in wild_msgs.iter().map(|m| Message::from_slice(&m[..]).unwrap()) {
let sig = s.sign(&msg, &key); let sig = s.sign_ecdsa(&msg, &key);
let low_r_sig = s.sign_low_r(&msg, &key); let low_r_sig = s.sign_ecdsa_low_r(&msg, &key);
let grind_r_sig = s.sign_grind_r(&msg, &key, 1); let grind_r_sig = s.sign_ecdsa_grind_r(&msg, &key, 1);
let pk = PublicKey::from_secret_key(&s, &key); let pk = PublicKey::from_secret_key(&s, &key);
assert_eq!(s.verify(&msg, &sig, &pk), Ok(())); assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Ok(()));
assert_eq!(s.verify(&msg, &low_r_sig, &pk), Ok(())); assert_eq!(s.verify_ecdsa(&msg, &low_r_sig, &pk), Ok(()));
assert_eq!(s.verify(&msg, &grind_r_sig, &pk), Ok(())); assert_eq!(s.verify_ecdsa(&msg, &grind_r_sig, &pk), Ok(()));
} }
} }
} }
@ -1186,25 +750,25 @@ mod tests {
let (sk, pk) = s.generate_keypair(&mut thread_rng()); let (sk, pk) = s.generate_keypair(&mut thread_rng());
let sig = s.sign(&msg, &sk); let sig = s.sign_ecdsa(&msg, &sk);
let mut msg = [0u8; 32]; let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg); thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
assert_eq!(s.verify(&msg, &sig, &pk), Err(IncorrectSignature)); assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Err(Error::IncorrectSignature));
} }
#[test] #[test]
fn test_bad_slice() { fn test_bad_slice() {
assert_eq!(Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE + 1]), assert_eq!(ecdsa::Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE + 1]),
Err(InvalidSignature)); Err(Error::InvalidSignature));
assert_eq!(Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE]), assert_eq!(ecdsa::Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE]),
Err(InvalidSignature)); Err(Error::InvalidSignature));
assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE - 1]), assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE - 1]),
Err(InvalidMessage)); Err(Error::InvalidMessage));
assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE + 1]), assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE + 1]),
Err(InvalidMessage)); Err(Error::InvalidMessage));
assert!(Message::from_slice(&[0; constants::MESSAGE_SIZE]).is_ok()); assert!(Message::from_slice(&[0; constants::MESSAGE_SIZE]).is_ok());
assert!(Message::from_slice(&[1; constants::MESSAGE_SIZE]).is_ok()); assert!(Message::from_slice(&[1; constants::MESSAGE_SIZE]).is_ok());
} }
@ -1246,15 +810,15 @@ mod tests {
let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d");
let secp = Secp256k1::new(); let secp = Secp256k1::new();
let mut sig = Signature::from_der(&sig[..]).unwrap(); let mut sig = ecdsa::Signature::from_der(&sig[..]).unwrap();
let pk = PublicKey::from_slice(&pk[..]).unwrap(); let pk = PublicKey::from_slice(&pk[..]).unwrap();
let msg = Message::from_slice(&msg[..]).unwrap(); let msg = Message::from_slice(&msg[..]).unwrap();
// without normalization we expect this will fail // without normalization we expect this will fail
assert_eq!(secp.verify(&msg, &sig, &pk), Err(IncorrectSignature)); assert_eq!(secp.verify_ecdsa(&msg, &sig, &pk), Err(Error::IncorrectSignature));
// after normalization it should pass // after normalization it should pass
sig.normalize_s(); sig.normalize_s();
assert_eq!(secp.verify(&msg, &sig, &pk), Ok(())); assert_eq!(secp.verify_ecdsa(&msg, &sig, &pk), Ok(()));
} }
#[test] #[test]
@ -1265,9 +829,9 @@ mod tests {
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap(); let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap();
let expected_sig = hex!("047dd4d049db02b430d24c41c7925b2725bcd5a85393513bdec04b4dc363632b1054d0180094122b380f4cfa391e6296244da773173e78fc745c1b9c79f7b713"); let expected_sig = hex!("047dd4d049db02b430d24c41c7925b2725bcd5a85393513bdec04b4dc363632b1054d0180094122b380f4cfa391e6296244da773173e78fc745c1b9c79f7b713");
let expected_sig = Signature::from_compact(&expected_sig).unwrap(); let expected_sig = ecdsa::Signature::from_compact(&expected_sig).unwrap();
let sig = secp.sign_low_r(&msg, &sk); let sig = secp.sign_ecdsa_low_r(&msg, &sk);
assert_eq!(expected_sig, sig); assert_eq!(expected_sig, sig);
} }
@ -1279,9 +843,9 @@ mod tests {
let msg = hex!("ef2d5b9a7c61865a95941d0f04285420560df7e9d76890ac1b8867b12ce43167"); let msg = hex!("ef2d5b9a7c61865a95941d0f04285420560df7e9d76890ac1b8867b12ce43167");
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
let sk = SecretKey::from_str("848355d75fe1c354cf05539bb29b2015f1863065bcb6766b44d399ab95c3fa0b").unwrap(); let sk = SecretKey::from_str("848355d75fe1c354cf05539bb29b2015f1863065bcb6766b44d399ab95c3fa0b").unwrap();
let expected_sig = Signature::from_str("304302202ffc447100d518c8ba643d11f3e6a83a8640488e7d2537b1954b942408be6ea3021f26e1248dd1e52160c3a38af9769d91a1a806cab5f9d508c103464d3c02d6e1").unwrap(); let expected_sig = ecdsa::Signature::from_str("304302202ffc447100d518c8ba643d11f3e6a83a8640488e7d2537b1954b942408be6ea3021f26e1248dd1e52160c3a38af9769d91a1a806cab5f9d508c103464d3c02d6e1").unwrap();
let sig = secp.sign_grind_r(&msg, &sk, 2); let sig = secp.sign_ecdsa_grind_r(&msg, &sk, 2);
assert_eq!(expected_sig, sig); assert_eq!(expected_sig, sig);
} }
@ -1296,7 +860,7 @@ mod tests {
let msg = Message::from_slice(&[1; 32]).unwrap(); let msg = Message::from_slice(&[1; 32]).unwrap();
let sk = SecretKey::from_slice(&[2; 32]).unwrap(); let sk = SecretKey::from_slice(&[2; 32]).unwrap();
let sig = s.sign(&msg, &sk); let sig = s.sign_ecdsa(&msg, &sk);
static SIG_BYTES: [u8; 71] = [ static SIG_BYTES: [u8; 71] = [
48, 69, 2, 33, 0, 157, 11, 173, 87, 103, 25, 211, 42, 231, 107, 237, 48, 69, 2, 33, 0, 157, 11, 173, 87, 103, 25, 211, 42, 231, 107, 237,
179, 76, 119, 72, 102, 103, 60, 189, 227, 244, 225, 41, 81, 85, 92, 148, 179, 76, 119, 72, 102, 103, 60, 189, 227, 244, 225, 41, 81, 85, 92, 148,
@ -1333,8 +897,8 @@ mod tests {
let pk = PublicKey::from_secret_key(&SECP256K1, &sk); let pk = PublicKey::from_secret_key(&SECP256K1, &sk);
// Check usage as self // Check usage as self
let sig = SECP256K1.sign(&msg, &sk); let sig = SECP256K1.sign_ecdsa(&msg, &sk);
assert!(SECP256K1.verify(&msg, &sig, &pk).is_ok()); assert!(SECP256K1.verify_ecdsa(&msg, &sig, &pk).is_ok());
} }
#[cfg(feature = "bitcoin_hashes")] #[cfg(feature = "bitcoin_hashes")]
@ -1406,7 +970,7 @@ mod benches {
} }
#[bench] #[bench]
pub fn bench_sign(bh: &mut Bencher) { pub fn bench_sign_ecdsa(bh: &mut Bencher) {
let s = Secp256k1::new(); let s = Secp256k1::new();
let mut msg = [0u8; 32]; let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg); thread_rng().fill_bytes(&mut msg);
@ -1414,22 +978,22 @@ mod benches {
let (sk, _) = s.generate_keypair(&mut thread_rng()); let (sk, _) = s.generate_keypair(&mut thread_rng());
bh.iter(|| { bh.iter(|| {
let sig = s.sign(&msg, &sk); let sig = s.sign_ecdsa(&msg, &sk);
black_box(sig); black_box(sig);
}); });
} }
#[bench] #[bench]
pub fn bench_verify(bh: &mut Bencher) { pub fn bench_verify_ecdsa(bh: &mut Bencher) {
let s = Secp256k1::new(); let s = Secp256k1::new();
let mut msg = [0u8; 32]; let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg); thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng()); let (sk, pk) = s.generate_keypair(&mut thread_rng());
let sig = s.sign(&msg, &sk); let sig = s.sign_ecdsa(&msg, &sk);
bh.iter(|| { bh.iter(|| {
let res = s.verify(&msg, &sig, &pk).unwrap(); let res = s.verify_ecdsa(&msg, &sig, &pk).unwrap();
black_box(res); black_box(res);
}); });
} }

View File

@ -11,8 +11,7 @@ use super::{from_hex, Error};
use core::{fmt, ptr, str}; use core::{fmt, ptr, str};
use ffi::{self, CPtr}; use ffi::{self, CPtr};
use {constants, Secp256k1}; use {constants, Secp256k1};
use {Message, Signing, Verification}; use {Message, Signing, KeyPair, XOnlyPublicKey};
use SecretKey;
/// Represents a Schnorr signature. /// Represents a Schnorr signature.
pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]); pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]);
@ -74,44 +73,6 @@ impl str::FromStr for Signature {
} }
} }
/// Opaque data structure that holds a keypair consisting of a secret and a public key.
#[derive(Clone)]
pub struct KeyPair(ffi::KeyPair);
impl_display_secret!(KeyPair);
/// A Schnorr public key, used for verification of Schnorr signatures
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
pub struct PublicKey(ffi::XOnlyPublicKey);
impl fmt::LowerHex for PublicKey {
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 PublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(self, f)
}
}
impl str::FromStr for PublicKey {
type Err = Error;
fn from_str(s: &str) -> Result<PublicKey, Error> {
let mut res = [0u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE];
match from_hex(s, &mut res) {
Ok(constants::SCHNORRSIG_PUBLIC_KEY_SIZE) => {
PublicKey::from_slice(&res[0..constants::SCHNORRSIG_PUBLIC_KEY_SIZE])
}
_ => Err(Error::InvalidPublicKey),
}
}
}
impl Signature { impl Signature {
/// Creates a Signature directly from a slice /// Creates a Signature directly from a slice
#[inline] #[inline]
@ -127,382 +88,6 @@ impl Signature {
} }
} }
impl KeyPair {
/// Obtains a raw const pointer suitable for use with FFI functions
#[inline]
pub fn as_ptr(&self) -> *const ffi::KeyPair {
&self.0
}
/// Obtains a raw mutable pointer suitable for use with FFI functions
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut ffi::KeyPair {
&mut self.0
}
/// Creates a Schnorr KeyPair directly from generic Secp256k1 secret key
///
/// # Panic
///
/// Panics if internal representation of the provided [`SecretKey`] does not hold correct secret
/// key value obtained from Secp256k1 library previously, specifically when secret key value is
/// out-of-range (0 or in excess of the group order).
#[inline]
pub fn from_secret_key<C: Signing>(
secp: &Secp256k1<C>,
sk: ::key::SecretKey,
) -> KeyPair {
unsafe {
let mut kp = ffi::KeyPair::new();
if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, sk.as_c_ptr()) == 1 {
KeyPair(kp)
} else {
panic!("the provided secret key is invalid: it is corrupted or was not produced by Secp256k1 library")
}
}
}
/// Creates a Schnorr KeyPair directly from a secret key slice.
///
/// # Errors
///
/// [`Error::InvalidSecretKey`] if the provided data has an incorrect length, exceeds Secp256k1
/// field `p` value or the corresponding public key is not even.
#[inline]
pub fn from_seckey_slice<C: Signing>(
secp: &Secp256k1<C>,
data: &[u8],
) -> Result<KeyPair, Error> {
if data.is_empty() || data.len() != constants::SECRET_KEY_SIZE {
return Err(Error::InvalidSecretKey);
}
unsafe {
let mut kp = ffi::KeyPair::new();
if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, data.as_c_ptr()) == 1 {
Ok(KeyPair(kp))
} else {
Err(Error::InvalidSecretKey)
}
}
}
/// Creates a Schnorr KeyPair directly from a secret key string
///
/// # Errors
///
/// [`Error::InvalidSecretKey`] if corresponding public key for the provided secret key is not even.
#[inline]
pub fn from_seckey_str<C: Signing>(secp: &Secp256k1<C>, s: &str) -> Result<KeyPair, Error> {
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])
}
_ => Err(Error::InvalidPublicKey),
}
}
/// Creates a new random secret key. Requires compilation with the "rand" feature.
#[inline]
#[cfg(any(test, feature = "rand"))]
pub fn new<R: Rng + ?Sized, C: Signing>(secp: &Secp256k1<C>, rng: &mut R) -> KeyPair {
let mut random_32_bytes = || {
let mut ret = [0u8; 32];
rng.fill_bytes(&mut ret);
ret
};
let mut data = random_32_bytes();
unsafe {
let mut keypair = ffi::KeyPair::new();
while ffi::secp256k1_keypair_create(secp.ctx, &mut keypair, data.as_c_ptr()) == 0 {
data = random_32_bytes();
}
KeyPair(keypair)
}
}
/// Serialize the key pair as a secret key byte value
#[inline]
pub fn serialize_secret(&self) -> [u8; constants::SECRET_KEY_SIZE] {
*SecretKey::from_keypair(self).as_ref()
}
/// Tweak a keypair by adding the given tweak to the secret key and updating the public key
/// accordingly.
///
/// Will return an error if the resulting key would be invalid or if the tweak was not a 32-byte
/// length slice.
///
/// NB: Will not error if the tweaked public key has an odd value and can't be used for
/// BIP 340-342 purposes.
// TODO: Add checked implementation
#[inline]
pub fn tweak_add_assign<C: Verification>(
&mut self,
secp: &Secp256k1<C>,
tweak: &[u8],
) -> Result<(), Error> {
if tweak.len() != 32 {
return Err(Error::InvalidTweak);
}
unsafe {
let err = ffi::secp256k1_keypair_xonly_tweak_add(
secp.ctx,
&mut self.0,
tweak.as_c_ptr(),
);
if err == 1 {
Ok(())
} else {
Err(Error::InvalidTweak)
}
}
}
}
impl PublicKey {
/// 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) -> PublicKey {
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);
PublicKey(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<PublicKey, 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(PublicKey(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 PublicKey {
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 PublicKey {
#[inline]
fn from(pk: ffi::XOnlyPublicKey) -> PublicKey {
PublicKey(pk)
}
}
impl From<::key::PublicKey> for PublicKey {
fn from(src: ::key::PublicKey) -> PublicKey {
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(),
)
);
PublicKey(pk)
}
}
}
#[cfg(feature = "serde")]
impl ::serde::Serialize for PublicKey {
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 PublicKey {
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",
PublicKey::from_slice
))
}
}
}
impl From<KeyPair> for SecretKey {
#[inline]
fn from(pair: KeyPair) -> Self {
SecretKey::from_keypair(&pair)
}
}
impl<'a> From<&'a KeyPair> for SecretKey {
#[inline]
fn from(pair: &'a KeyPair) -> Self {
SecretKey::from_keypair(pair)
}
}
impl From<KeyPair> for ::key::PublicKey {
#[inline]
fn from(pair: KeyPair) -> Self {
::key::PublicKey::from_keypair(&pair)
}
}
impl<'a> From<&'a KeyPair> for ::key::PublicKey {
#[inline]
fn from(pair: &'a KeyPair) -> Self {
::key::PublicKey::from_keypair(pair)
}
}
impl<C: Signing> Secp256k1<C> { impl<C: Signing> Secp256k1<C> {
fn schnorrsig_sign_helper( fn schnorrsig_sign_helper(
&self, &self,
@ -532,26 +117,56 @@ impl<C: Signing> Secp256k1<C> {
/// generator to generate the auxiliary random data. /// generator to generate the auxiliary random data.
/// Requires compilation with "rand-std" feature. /// Requires compilation with "rand-std" feature.
#[cfg(any(test, feature = "rand-std"))] #[cfg(any(test, feature = "rand-std"))]
#[deprecated(since = "0.21.0", note = "Use sign_schnorr instead.")]
pub fn schnorrsig_sign(&self, msg: &Message, keypair: &KeyPair) -> Signature { pub fn schnorrsig_sign(&self, msg: &Message, keypair: &KeyPair) -> Signature {
self.sign_schnorr(msg, keypair)
}
/// Create a schnorr signature internally using the ThreadRng random number
/// generator to generate the auxiliary random data.
/// Requires compilation with "rand-std" feature.
#[cfg(any(test, feature = "rand-std"))]
pub fn sign_schnorr(&self, msg: &Message, keypair: &KeyPair) -> Signature {
let mut rng = thread_rng(); let mut rng = thread_rng();
self.schnorrsig_sign_with_rng(msg, keypair, &mut rng) self.sign_schnorr_with_rng(msg, keypair, &mut rng)
} }
/// Create a schnorr signature without using any auxiliary random data. /// Create a schnorr signature without using any auxiliary random data.
#[deprecated(since = "0.21.0", note = "Use sign_schnorr_no_aux_rand instead.")]
pub fn schnorrsig_sign_no_aux_rand( pub fn schnorrsig_sign_no_aux_rand(
&self, &self,
msg: &Message, msg: &Message,
keypair: &KeyPair, keypair: &KeyPair,
) -> Signature {
self.sign_schnorr_no_aux_rand(msg, keypair)
}
/// Create a schnorr signature without using any auxiliary random data.
pub fn sign_schnorr_no_aux_rand(
&self,
msg: &Message,
keypair: &KeyPair,
) -> Signature { ) -> Signature {
self.schnorrsig_sign_helper(msg, keypair, ptr::null()) self.schnorrsig_sign_helper(msg, keypair, ptr::null())
} }
/// Create a Schnorr signature using the given auxiliary random data. /// Create a Schnorr signature using the given auxiliary random data.
#[deprecated(since = "0.21.0", note = "Use sign_schnorr_with_aux_rand instead.")]
pub fn schnorrsig_sign_with_aux_rand( pub fn schnorrsig_sign_with_aux_rand(
&self, &self,
msg: &Message, msg: &Message,
keypair: &KeyPair, keypair: &KeyPair,
aux_rand: &[u8; 32], aux_rand: &[u8; 32],
) -> Signature {
self.sign_schnorr_with_aux_rand(msg, keypair, aux_rand)
}
/// Create a Schnorr signature using the given auxiliary random data.
pub fn sign_schnorr_with_aux_rand(
&self,
msg: &Message,
keypair: &KeyPair,
aux_rand: &[u8; 32],
) -> Signature { ) -> Signature {
self.schnorrsig_sign_helper( self.schnorrsig_sign_helper(
msg, msg,
@ -564,11 +179,25 @@ impl<C: Signing> Secp256k1<C> {
/// generate the auxiliary random data. Requires compilation with "rand" /// generate the auxiliary random data. Requires compilation with "rand"
/// feature. /// feature.
#[cfg(any(test, feature = "rand"))] #[cfg(any(test, feature = "rand"))]
#[deprecated(since = "0.21.0", note = "Use sign_schnorr_with_rng instead.")]
pub fn schnorrsig_sign_with_rng<R: Rng + CryptoRng>( pub fn schnorrsig_sign_with_rng<R: Rng + CryptoRng>(
&self, &self,
msg: &Message, msg: &Message,
keypair: &KeyPair, keypair: &KeyPair,
rng: &mut R, rng: &mut R,
) -> Signature {
self.sign_schnorr_with_rng(msg, keypair, rng)
}
/// Create a schnorr signature using the given random number generator to
/// generate the auxiliary random data. Requires compilation with "rand"
/// feature.
#[cfg(any(test, feature = "rand"))]
pub fn sign_schnorr_with_rng<R: Rng + CryptoRng>(
&self,
msg: &Message,
keypair: &KeyPair,
rng: &mut R,
) -> Signature { ) -> Signature {
let mut aux = [0u8; 32]; let mut aux = [0u8; 32];
rng.fill_bytes(&mut aux); rng.fill_bytes(&mut aux);
@ -576,11 +205,22 @@ impl<C: Signing> Secp256k1<C> {
} }
/// Verify a Schnorr signature. /// Verify a Schnorr signature.
#[deprecated(since = "0.21.0", note = "Use verify_schnorr instead.")]
pub fn schnorrsig_verify( pub fn schnorrsig_verify(
&self, &self,
sig: &Signature, sig: &Signature,
msg: &Message, msg: &Message,
pubkey: &PublicKey, pubkey: &XOnlyPublicKey,
) -> Result<(), Error> {
self.verify_schnorr(sig, msg, pubkey)
}
/// Verify a Schnorr signature.
pub fn verify_schnorr(
&self,
sig: &Signature,
msg: &Message,
pubkey: &XOnlyPublicKey,
) -> Result<(), Error> { ) -> Result<(), Error> {
unsafe { unsafe {
let ret = ffi::secp256k1_schnorrsig_verify( let ret = ffi::secp256k1_schnorrsig_verify(
@ -608,9 +248,9 @@ impl<C: Signing> Secp256k1<C> {
pub fn generate_schnorrsig_keypair<R: Rng + ?Sized>( pub fn generate_schnorrsig_keypair<R: Rng + ?Sized>(
&self, &self,
rng: &mut R, rng: &mut R,
) -> (KeyPair, PublicKey) { ) -> (KeyPair, XOnlyPublicKey) {
let sk = KeyPair::new(self, rng); let sk = KeyPair::new(self, rng);
let pubkey = PublicKey::from_keypair(self, &sk); let pubkey = XOnlyPublicKey::from_keypair(self, &sk);
(sk, pubkey) (sk, pubkey)
} }
} }
@ -619,7 +259,7 @@ impl<C: Signing> Secp256k1<C> {
mod tests { mod tests {
use super::super::Error::InvalidPublicKey; use super::super::Error::InvalidPublicKey;
use super::super::{constants, from_hex, All, Message, Secp256k1}; use super::super::{constants, from_hex, All, Message, Secp256k1};
use super::{KeyPair, PublicKey, Signature}; use super::{KeyPair, XOnlyPublicKey, Signature};
use rand::{rngs::ThreadRng, thread_rng, Error, ErrorKind, RngCore}; use rand::{rngs::ThreadRng, thread_rng, Error, ErrorKind, RngCore};
use rand_core::impls; use rand_core::impls;
use std::iter; use std::iter;
@ -637,6 +277,36 @@ mod tests {
}}; }};
} }
#[test]
fn test_schnorrsig_sign_with_aux_rand_verify() {
test_schnorrsig_sign_helper(|secp, msg, seckey, rng| {
let mut aux_rand = [0u8; 32];
rng.fill_bytes(&mut aux_rand);
secp.sign_schnorr_with_aux_rand(msg, seckey, &aux_rand)
})
}
#[test]
fn test_schnorrsig_sign_with_rng_verify() {
test_schnorrsig_sign_helper(|secp, msg, seckey, mut rng| {
secp.sign_schnorr_with_rng(msg, seckey, &mut rng)
})
}
#[test]
fn test_schnorrsig_sign_verify() {
test_schnorrsig_sign_helper(|secp, msg, seckey, _| {
secp.sign_schnorr(msg, seckey)
})
}
#[test]
fn test_schnorrsig_sign_no_aux_rand_verify() {
test_schnorrsig_sign_helper(|secp, msg, seckey, _| {
secp.sign_schnorr_no_aux_rand(msg, seckey)
})
}
fn test_schnorrsig_sign_helper( fn test_schnorrsig_sign_helper(
sign: fn(&Secp256k1<All>, &Message, &KeyPair, &mut ThreadRng) -> Signature, sign: fn(&Secp256k1<All>, &Message, &KeyPair, &mut ThreadRng) -> Signature,
) { ) {
@ -652,40 +322,10 @@ mod tests {
let sig = sign(&secp, &msg, &seckey, &mut rng); let sig = sign(&secp, &msg, &seckey, &mut rng);
assert!(secp.schnorrsig_verify(&sig, &msg, &pubkey).is_ok()); assert!(secp.verify_schnorr(&sig, &msg, &pubkey).is_ok());
} }
} }
#[test]
fn test_schnorrsig_sign_with_aux_rand_verify() {
test_schnorrsig_sign_helper(|secp, msg, seckey, rng| {
let mut aux_rand = [0u8; 32];
rng.fill_bytes(&mut aux_rand);
secp.schnorrsig_sign_with_aux_rand(msg, seckey, &aux_rand)
})
}
#[test]
fn test_schnorrsig_sign_with_rng_verify() {
test_schnorrsig_sign_helper(|secp, msg, seckey, mut rng| {
secp.schnorrsig_sign_with_rng(msg, seckey, &mut rng)
})
}
#[test]
fn test_schnorrsig_sign_verify() {
test_schnorrsig_sign_helper(|secp, msg, seckey, _| {
secp.schnorrsig_sign(msg, seckey)
})
}
#[test]
fn test_schnorrsig_sign_no_aux_rand_verify() {
test_schnorrsig_sign_helper(|secp, msg, seckey, _| {
secp.schnorrsig_sign_no_aux_rand(msg, seckey)
})
}
#[test] #[test]
#[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs #[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs
fn test_schnorrsig_sign() { fn test_schnorrsig_sign() {
@ -703,7 +343,7 @@ mod tests {
let expected_sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap(); let expected_sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap();
let sig = secp let sig = secp
.schnorrsig_sign_with_aux_rand(&msg, &sk, &aux_rand); .sign_schnorr_with_aux_rand(&msg, &sk, &aux_rand);
assert_eq!(expected_sig, sig); assert_eq!(expected_sig, sig);
} }
@ -717,17 +357,17 @@ mod tests {
let msg = Message::from_slice(&hex_msg).unwrap(); let msg = Message::from_slice(&hex_msg).unwrap();
let sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap(); let sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap();
let pubkey = let pubkey =
PublicKey::from_str("B33CC9EDC096D0A83416964BD3C6247B8FECD256E4EFA7870D2C854BDEB33390") XOnlyPublicKey::from_str("B33CC9EDC096D0A83416964BD3C6247B8FECD256E4EFA7870D2C854BDEB33390")
.unwrap(); .unwrap();
assert!(secp.schnorrsig_verify(&sig, &msg, &pubkey).is_ok()); assert!(secp.verify_schnorr(&sig, &msg, &pubkey).is_ok());
} }
#[test] #[test]
fn test_pubkey_from_slice() { fn test_pubkey_from_slice() {
assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey)); assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey));
assert_eq!(PublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey)); assert_eq!(XOnlyPublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey));
let pk = PublicKey::from_slice(&[ let pk = XOnlyPublicKey::from_slice(&[
0xB3, 0x3C, 0xC9, 0xED, 0xC0, 0x96, 0xD0, 0xA8, 0x34, 0x16, 0x96, 0x4B, 0xD3, 0xC6, 0xB3, 0x3C, 0xC9, 0xED, 0xC0, 0x96, 0xD0, 0xA8, 0x34, 0x16, 0x96, 0x4B, 0xD3, 0xC6,
0x24, 0x7B, 0x8F, 0xEC, 0xD2, 0x56, 0xE4, 0xEF, 0xA7, 0x87, 0x0D, 0x2C, 0x85, 0x4B, 0x24, 0x7B, 0x8F, 0xEC, 0xD2, 0x56, 0xE4, 0xEF, 0xA7, 0x87, 0x0D, 0x2C, 0x85, 0x4B,
0xDE, 0xB3, 0x33, 0x90, 0xDE, 0xB3, 0x33, 0x90,
@ -740,7 +380,7 @@ mod tests {
let secp = Secp256k1::new(); let secp = Secp256k1::new();
let (_, pubkey) = secp.generate_schnorrsig_keypair(&mut thread_rng()); let (_, pubkey) = secp.generate_schnorrsig_keypair(&mut thread_rng());
let ser = pubkey.serialize(); let ser = pubkey.serialize();
let pubkey2 = PublicKey::from_slice(&ser).unwrap(); let pubkey2 = XOnlyPublicKey::from_slice(&ser).unwrap();
assert_eq!(pubkey, pubkey2); assert_eq!(pubkey, pubkey2);
} }
@ -753,35 +393,35 @@ mod tests {
assert_eq!(SecretKey::from_str(sk_str).unwrap(), sk); assert_eq!(SecretKey::from_str(sk_str).unwrap(), sk);
let pk = ::key::PublicKey::from_keypair(&keypair); let pk = ::key::PublicKey::from_keypair(&keypair);
assert_eq!(::key::PublicKey::from_secret_key(&secp, &sk), pk); assert_eq!(::key::PublicKey::from_secret_key(&secp, &sk), pk);
let xpk = PublicKey::from_keypair(&secp, &keypair); let xpk = XOnlyPublicKey::from_keypair(&secp, &keypair);
assert_eq!(PublicKey::from(pk), xpk); assert_eq!(XOnlyPublicKey::from(pk), xpk);
} }
#[test] #[test]
fn test_pubkey_from_bad_slice() { fn test_pubkey_from_bad_slice() {
// Bad sizes // Bad sizes
assert_eq!( assert_eq!(
PublicKey::from_slice(&[0; constants::SCHNORRSIG_PUBLIC_KEY_SIZE - 1]), XOnlyPublicKey::from_slice(&[0; constants::SCHNORRSIG_PUBLIC_KEY_SIZE - 1]),
Err(InvalidPublicKey) Err(InvalidPublicKey)
); );
assert_eq!( assert_eq!(
PublicKey::from_slice(&[0; constants::SCHNORRSIG_PUBLIC_KEY_SIZE + 1]), XOnlyPublicKey::from_slice(&[0; constants::SCHNORRSIG_PUBLIC_KEY_SIZE + 1]),
Err(InvalidPublicKey) Err(InvalidPublicKey)
); );
// Bad parse // Bad parse
assert_eq!( assert_eq!(
PublicKey::from_slice(&[0xff; constants::SCHNORRSIG_PUBLIC_KEY_SIZE]), XOnlyPublicKey::from_slice(&[0xff; constants::SCHNORRSIG_PUBLIC_KEY_SIZE]),
Err(InvalidPublicKey) Err(InvalidPublicKey)
); );
// In fuzzing mode restrictions on public key validity are much more // In fuzzing mode restrictions on public key validity are much more
// relaxed, thus the invalid check below is expected to fail. // relaxed, thus the invalid check below is expected to fail.
#[cfg(not(fuzzing))] #[cfg(not(fuzzing))]
assert_eq!( assert_eq!(
PublicKey::from_slice(&[0x55; constants::SCHNORRSIG_PUBLIC_KEY_SIZE]), XOnlyPublicKey::from_slice(&[0x55; constants::SCHNORRSIG_PUBLIC_KEY_SIZE]),
Err(InvalidPublicKey) Err(InvalidPublicKey)
); );
assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey)); assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey));
} }
#[test] #[test]
@ -799,43 +439,43 @@ mod tests {
// In fuzzing mode secret->public key derivation is different, so // In fuzzing mode secret->public key derivation is different, so
// hard-code the epected result. // hard-code the epected result.
#[cfg(not(fuzzing))] #[cfg(not(fuzzing))]
let pk = PublicKey::from_keypair(&s, &sk); let pk = XOnlyPublicKey::from_keypair(&s, &sk);
#[cfg(fuzzing)] #[cfg(fuzzing)]
let pk = PublicKey::from_slice(&[0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, 0x06, 0x7d, 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, 0x4a, 0xc8, 0x87, 0xfe, 0x91, 0xdd, 0xd1, 0x66]).expect("pk"); let pk = XOnlyPublicKey::from_slice(&[0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, 0x06, 0x7d, 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, 0x4a, 0xc8, 0x87, 0xfe, 0x91, 0xdd, 0xd1, 0x66]).expect("pk");
assert_eq!( assert_eq!(
pk.to_string(), pk.to_string(),
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166" "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"
); );
assert_eq!( assert_eq!(
PublicKey::from_str("18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166") XOnlyPublicKey::from_str("18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166")
.unwrap(), .unwrap(),
pk pk
); );
assert!(PublicKey::from_str( assert!(XOnlyPublicKey::from_str(
"00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000"
) )
.is_err()); .is_err());
assert!(PublicKey::from_str( assert!(XOnlyPublicKey::from_str(
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16601" "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16601"
) )
.is_err()); .is_err());
assert!(PublicKey::from_str( assert!(XOnlyPublicKey::from_str(
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16" "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16"
) )
.is_err()); .is_err());
assert!(PublicKey::from_str( assert!(XOnlyPublicKey::from_str(
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1" "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1"
) )
.is_err()); .is_err());
assert!(PublicKey::from_str( assert!(XOnlyPublicKey::from_str(
"xx18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1" "xx18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1"
) )
.is_err()); .is_err());
let long_str: String = iter::repeat('a').take(1024 * 1024).collect(); let long_str: String = iter::repeat('a').take(1024 * 1024).collect();
assert!(PublicKey::from_str(&long_str).is_err()); assert!(XOnlyPublicKey::from_str(&long_str).is_err());
} }
#[test] #[test]
@ -884,7 +524,7 @@ mod tests {
let keypair = KeyPair::from_seckey_slice(&s, &[2; 32]).unwrap(); let keypair = KeyPair::from_seckey_slice(&s, &[2; 32]).unwrap();
let aux = [3u8; 32]; let aux = [3u8; 32];
let sig = s let sig = s
.schnorrsig_sign_with_aux_rand(&msg, &keypair, &aux); .sign_schnorr_with_aux_rand(&msg, &keypair, &aux);
static SIG_BYTES: [u8; constants::SCHNORRSIG_SIGNATURE_SIZE] = [ static SIG_BYTES: [u8; constants::SCHNORRSIG_SIGNATURE_SIZE] = [
0x14, 0xd0, 0xbf, 0x1a, 0x89, 0x53, 0x50, 0x6f, 0xb4, 0x60, 0xf5, 0x8b, 0xe1, 0x41, 0x14, 0xd0, 0xbf, 0x1a, 0x89, 0x53, 0x50, 0x6f, 0xb4, 0x60, 0xf5, 0x8b, 0xe1, 0x41,
0xaf, 0x76, 0x7f, 0xd1, 0x12, 0x53, 0x5f, 0xb3, 0x92, 0x2e, 0xf2, 0x17, 0x30, 0x8e, 0xaf, 0x76, 0x7f, 0xd1, 0x12, 0x53, 0x5f, 0xb3, 0x92, 0x2e, 0xf2, 0x17, 0x30, 0x8e,
@ -903,7 +543,7 @@ mod tests {
static PK_STR: &'static str = "\ static PK_STR: &'static str = "\
18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\ 18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\
"; ";
let pk = PublicKey::from_slice(&PK_BYTES).unwrap(); let pk = XOnlyPublicKey::from_slice(&PK_BYTES).unwrap();
assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]); assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]);
assert_tokens(&sig.compact(), &[Token::Bytes(&SIG_BYTES[..])]); assert_tokens(&sig.compact(), &[Token::Bytes(&SIG_BYTES[..])]);
@ -932,7 +572,7 @@ mod tests {
let orig_pk = pk; let orig_pk = pk;
kp.tweak_add_assign(&s, &tweak).expect("Tweak error"); kp.tweak_add_assign(&s, &tweak).expect("Tweak error");
let parity = pk.tweak_add_assign(&s, &tweak).expect("Tweak error"); let parity = pk.tweak_add_assign(&s, &tweak).expect("Tweak error");
assert_eq!(PublicKey::from_keypair(&s, &kp), pk); assert_eq!(XOnlyPublicKey::from_keypair(&s, &kp), pk);
assert!(orig_pk.tweak_add_check(&s, &pk, parity, tweak)); assert!(orig_pk.tweak_add_check(&s, &pk, parity, tweak));
} }
} }
@ -948,8 +588,8 @@ mod tests {
) )
.unwrap(); .unwrap();
let pk1 = PublicKey::from(kpk1); let pk1 = XOnlyPublicKey::from(kpk1);
let pk2 = PublicKey::from(kpk2); let pk2 = XOnlyPublicKey::from(kpk2);
assert_eq!(pk1.serialize()[..], kpk1.serialize()[1..]); assert_eq!(pk1.serialize()[..], kpk1.serialize()[1..]);
assert_eq!(pk2.serialize()[..], kpk2.serialize()[1..]); assert_eq!(pk2.serialize()[..], kpk2.serialize()[1..]);

View File

@ -15,7 +15,7 @@
//! Helpers for displaying secret values //! Helpers for displaying secret values
use ::core::fmt; use ::core::fmt;
use ::{SecretKey, schnorrsig::KeyPair, to_hex}; use ::{SecretKey, KeyPair, to_hex};
use constants::SECRET_KEY_SIZE; use constants::SECRET_KEY_SIZE;
macro_rules! impl_display_secret { macro_rules! impl_display_secret {
@ -90,7 +90,7 @@ impl SecretKey {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use secp256k1::key::ONE_KEY; /// use secp256k1::ONE_KEY;
/// let key = ONE_KEY; /// let key = ONE_KEY;
/// // Normal display hides value /// // Normal display hides value
/// assert_eq!( /// assert_eq!(
@ -123,8 +123,8 @@ impl KeyPair {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use secp256k1::key::ONE_KEY; /// use secp256k1::ONE_KEY;
/// use secp256k1::schnorrsig::KeyPair; /// use secp256k1::KeyPair;
/// use secp256k1::Secp256k1; /// use secp256k1::Secp256k1;
/// ///
/// let secp = Secp256k1::new(); /// let secp = Secp256k1::new();