#[cfg(feature = "recovery")]
mod recovery;
pub mod serialized_signature;
use core::{fmt, ptr, str};
#[cfg(feature = "recovery")]
pub use self::recovery::{RecoverableSignature, RecoveryId};
pub use self::serialized_signature::SerializedSignature;
use crate::ffi::CPtr;
use crate::{
ecdsa, ffi, from_hex, Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification,
};
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Signature(pub(crate) ffi::Signature);
impl_fast_comparisons!(Signature);
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();
sig.fmt(f)
}
}
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 Signature {
#[inline]
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_static,
&mut ret,
data.as_c_ptr(),
data.len(),
) == 1
{
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
}
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_static,
&mut ret,
data.as_c_ptr(),
) == 1
{
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
}
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_static,
&mut ret,
data.as_c_ptr(),
data.len(),
) == 1
{
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
}
pub fn normalize_s(&mut self) {
unsafe {
ffi::secp256k1_ecdsa_signature_normalize(
ffi::secp256k1_context_static,
self.as_mut_c_ptr(),
self.as_c_ptr(),
);
}
}
#[inline]
pub fn serialize_der(&self) -> SerializedSignature {
let mut data = [0u8; serialized_signature::MAX_LEN];
let mut len: usize = serialized_signature::MAX_LEN;
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_der(
ffi::secp256k1_context_static,
data.as_mut_ptr(),
&mut len,
self.as_c_ptr(),
);
debug_assert!(err == 1);
SerializedSignature::from_raw_parts(data, len)
}
}
#[inline]
pub fn serialize_compact(&self) -> [u8; 64] {
let mut ret = [0u8; 64];
unsafe {
let err = ffi::secp256k1_ecdsa_signature_serialize_compact(
ffi::secp256k1_context_static,
ret.as_mut_c_ptr(),
self.as_c_ptr(),
);
debug_assert!(err == 1);
}
ret
}
#[inline]
pub fn verify(&self, msg: impl Into<Message>, pk: &PublicKey) -> Result<(), Error> {
ecdsa::verify(self, msg, pk)
}
}
impl CPtr for Signature {
type Target = ffi::Signature;
fn as_c_ptr(&self) -> *const Self::Target { &self.0 }
fn as_mut_c_ptr(&mut self) -> *mut Self::Target { &mut self.0 }
}
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(crate::serde_util::FromStrVisitor::new(
"a hex string representing a DER encoded Signature",
))
} else {
d.deserialize_bytes(crate::serde_util::BytesVisitor::new(
"raw byte stream, that represents a DER encoded Signature",
Signature::from_der,
))
}
}
}
fn sign_ecdsa_with_noncedata_pointer(
msg: impl Into<Message>,
sk: &SecretKey,
noncedata: Option<&[u8; 32]>,
) -> Signature {
let msg = msg.into();
unsafe {
let mut ret = ffi::Signature::new();
let noncedata_ptr = match noncedata {
Some(arr) => arr.as_c_ptr().cast::<ffi::types::c_void>(),
None => ptr::null(),
};
let res = crate::with_global_context(
|secp: &Secp256k1<crate::AllPreallocated>| {
ffi::secp256k1_ecdsa_sign(
secp.ctx.as_ptr(),
&mut ret,
msg.as_c_ptr(),
sk.as_c_ptr(),
ffi::secp256k1_nonce_function_rfc6979,
noncedata_ptr,
)
},
Some(&sk.to_secret_bytes()),
);
assert_eq!(res, 1);
Signature::from(ret)
}
}
pub fn sign(msg: impl Into<Message>, sk: &SecretKey) -> Signature {
sign_ecdsa_with_noncedata_pointer(msg, sk, None)
}
pub fn sign_with_noncedata(
msg: impl Into<Message>,
sk: &SecretKey,
noncedata: &[u8; 32],
) -> Signature {
sign_ecdsa_with_noncedata_pointer(msg, sk, Some(noncedata))
}
fn sign_grind_with_check(
msg: impl Into<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];
let msg = msg.into();
loop {
unsafe {
let mut ret = ffi::Signature::new();
let res = crate::with_global_context(
|secp: &Secp256k1<crate::AllPreallocated>| {
ffi::secp256k1_ecdsa_sign(
secp.ctx.as_ptr(),
&mut ret,
msg.as_c_ptr(),
sk.as_c_ptr(),
ffi::secp256k1_nonce_function_rfc6979,
entropy_p,
)
},
Some(&sk.to_secret_bytes()),
);
assert_eq!(res, 1);
if check(&ret) {
return Signature::from(ret);
}
counter += 1;
extra_entropy[..4].copy_from_slice(&counter.to_le_bytes());
entropy_p = extra_entropy.as_c_ptr().cast::<ffi::types::c_void>();
#[cfg(secp256k1_fuzz)]
return Signature::from(ret);
}
}
}
pub fn sign_grind_r(msg: impl Into<Message>, sk: &SecretKey, bytes_to_grind: usize) -> Signature {
assert!(bytes_to_grind <= 71);
let len_check = |s: &ffi::Signature| der_length_check(s, 71 - bytes_to_grind);
sign_grind_with_check(msg, sk, len_check)
}
pub fn sign_low_r(msg: impl Into<Message>, sk: &SecretKey) -> Signature {
sign_grind_with_check(msg, sk, compact_sig_has_zero_first_bit)
}
impl<C: Signing> Secp256k1<C> {
#[deprecated(since = "0.33.0", note = "use ecdsa::sign instead")]
pub fn sign_ecdsa(&self, msg: impl Into<Message>, sk: &SecretKey) -> Signature {
self::sign(msg, sk)
}
#[deprecated(since = "0.33.0", note = "use ecdsa::sign_with_noncedata instead")]
pub fn sign_ecdsa_with_noncedata(
&self,
msg: impl Into<Message>,
sk: &SecretKey,
noncedata: &[u8; 32],
) -> Signature {
self::sign_with_noncedata(msg, sk, noncedata)
}
#[deprecated(since = "0.33.0", note = "use ecdsa::sign_grind_r instead")]
pub fn sign_ecdsa_grind_r(
&self,
msg: impl Into<Message>,
sk: &SecretKey,
bytes_to_grind: usize,
) -> Signature {
self::sign_grind_r(msg, sk, bytes_to_grind)
}
#[deprecated(since = "0.33.0", note = "use ecdsa::sign_low_r instead")]
pub fn sign_ecdsa_low_r(&self, msg: impl Into<Message>, sk: &SecretKey) -> Signature {
self::sign_low_r(msg, sk)
}
}
impl<C: Verification> Secp256k1<C> {
#[inline]
#[deprecated(since = "0.33.0", note = "use ecdsa::verify instead")]
pub fn verify_ecdsa(
&self,
msg: impl Into<Message>,
sig: &Signature,
pk: &PublicKey,
) -> Result<(), Error> {
self::verify(sig, msg, pk)
}
}
#[inline]
pub fn verify(sig: &Signature, msg: impl Into<Message>, pk: &PublicKey) -> Result<(), Error> {
let msg = msg.into();
unsafe {
let res = crate::with_global_context(
|secp: &Secp256k1<crate::AllPreallocated>| {
ffi::secp256k1_ecdsa_verify(
secp.ctx.as_ptr(),
sig.as_c_ptr(),
msg.as_c_ptr(),
pk.as_c_ptr(),
)
},
None,
);
if res == 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_static,
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_static,
ser_ret.as_mut_c_ptr(),
&mut len,
sig,
);
debug_assert!(err == 1);
}
len <= max_len
}
#[cfg(test)]
mod tests {
use crate::ecdsa::Signature;
use crate::Scalar;
#[test]
fn test_from_compact_min_r_and_min_s() {
let r = Scalar::ZERO;
let s = Scalar::ZERO;
let mut bytes: [u8; 64] = [0; 64];
bytes[..32].copy_from_slice(&r.to_be_bytes());
bytes[32..].copy_from_slice(&s.to_be_bytes());
assert!(Signature::from_compact(&bytes).is_ok())
}
#[test]
fn test_from_compact_max_r_and_max_s() {
let r = Scalar::MAX;
let s = Scalar::MAX;
let mut bytes: [u8; 64] = [0; 64];
bytes[..32].copy_from_slice(&r.to_be_bytes());
bytes[32..].copy_from_slice(&s.to_be_bytes());
assert!(Signature::from_compact(&bytes).is_ok())
}
#[test]
fn test_from_compact_invalid_r() {
let r = Scalar::MAX;
let s = Scalar::MAX;
let mut bytes: [u8; 64] = [0; 64];
bytes[..32].copy_from_slice(&r.to_be_bytes());
bytes[32..].copy_from_slice(&s.to_be_bytes());
bytes[31] += 1;
assert!(Signature::from_compact(&bytes).is_err())
}
#[test]
fn test_from_compact_invalid_s() {
let r = Scalar::MAX;
let s = Scalar::MAX;
let mut bytes: [u8; 64] = [0; 64];
bytes[..32].copy_from_slice(&r.to_be_bytes());
bytes[32..].copy_from_slice(&s.to_be_bytes());
bytes[63] += 1;
assert!(Signature::from_compact(&bytes).is_err())
}
}