2020-09-15 01:46:19 +00:00
|
|
|
//! # schnorrsig
|
|
|
|
//! Support for Schnorr signatures.
|
|
|
|
//!
|
|
|
|
|
|
|
|
#[cfg(any(test, feature = "rand-std"))]
|
|
|
|
use rand::thread_rng;
|
|
|
|
#[cfg(any(test, feature = "rand"))]
|
|
|
|
use rand::{CryptoRng, Rng};
|
|
|
|
|
|
|
|
use super::{from_hex, Error};
|
|
|
|
use core::{fmt, ptr, str};
|
|
|
|
use ffi::{self, CPtr};
|
|
|
|
use {constants, Secp256k1};
|
2021-12-23 19:16:33 +00:00
|
|
|
use {Message, Signing, Verification, KeyPair, XOnlyPublicKey};
|
2020-09-15 01:46:19 +00:00
|
|
|
|
2022-02-08 06:11:05 +00:00
|
|
|
#[cfg(all(feature = "global-context", feature = "rand-std"))]
|
|
|
|
use SECP256K1;
|
|
|
|
|
2020-09-15 01:46:19 +00:00
|
|
|
/// Represents a Schnorr signature.
|
|
|
|
pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]);
|
|
|
|
impl_array_newtype!(Signature, u8, constants::SCHNORRSIG_SIGNATURE_SIZE);
|
|
|
|
impl_pretty_debug!(Signature);
|
2020-05-15 12:37:08 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "serde")]
|
2022-01-04 15:55:01 +00:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
|
2020-05-15 12:37:08 +00:00
|
|
|
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[..])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "serde")]
|
2022-01-04 15:55:01 +00:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
|
2020-05-15 12:37:08 +00:00
|
|
|
impl<'de> ::serde::Deserialize<'de> for Signature {
|
|
|
|
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
|
|
|
if d.is_human_readable() {
|
2021-01-12 22:54:33 +00:00
|
|
|
d.deserialize_str(super::serde_util::FromStrVisitor::new(
|
2020-05-15 12:37:08 +00:00
|
|
|
"a hex string representing 64 byte schnorr signature"
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
|
|
|
|
"raw 64 bytes schnorr signature",
|
|
|
|
Signature::from_slice
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-15 01:46:19 +00:00
|
|
|
|
|
|
|
impl fmt::LowerHex for Signature {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
for ch in &self.0[..] {
|
|
|
|
write!(f, "{:02x}", ch)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Signature {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
fmt::LowerHex::fmt(self, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl str::FromStr for Signature {
|
|
|
|
type Err = Error;
|
|
|
|
fn from_str(s: &str) -> Result<Signature, Error> {
|
2021-10-17 01:07:51 +00:00
|
|
|
let mut res = [0u8; constants::SCHNORRSIG_SIGNATURE_SIZE];
|
2020-09-15 01:46:19 +00:00
|
|
|
match from_hex(s, &mut res) {
|
|
|
|
Ok(constants::SCHNORRSIG_SIGNATURE_SIZE) => {
|
|
|
|
Signature::from_slice(&res[0..constants::SCHNORRSIG_SIGNATURE_SIZE])
|
|
|
|
}
|
|
|
|
_ => Err(Error::InvalidSignature),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Signature {
|
|
|
|
/// Creates a Signature directly from a slice
|
|
|
|
#[inline]
|
|
|
|
pub fn from_slice(data: &[u8]) -> Result<Signature, Error> {
|
|
|
|
match data.len() {
|
|
|
|
constants::SCHNORRSIG_SIGNATURE_SIZE => {
|
2021-10-17 01:07:51 +00:00
|
|
|
let mut ret = [0u8; constants::SCHNORRSIG_SIGNATURE_SIZE];
|
2020-09-15 01:46:19 +00:00
|
|
|
ret[..].copy_from_slice(data);
|
|
|
|
Ok(Signature(ret))
|
|
|
|
}
|
2021-09-27 13:19:27 +00:00
|
|
|
_ => Err(Error::InvalidSignature),
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-08 06:11:05 +00:00
|
|
|
|
|
|
|
/// Verifies a schnorr signature for `msg` using `pk` and the global [`SECP256K1`] context.
|
|
|
|
#[inline]
|
|
|
|
#[cfg(all(feature = "global-context", feature = "rand-std"))]
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "global-context", feature = "rand-std"))))]
|
|
|
|
pub fn verify(&self, msg: &Message, pk: &XOnlyPublicKey) -> Result<(), Error> {
|
|
|
|
SECP256K1.verify_schnorr(self, msg, pk)
|
|
|
|
}
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<C: Signing> Secp256k1<C> {
|
|
|
|
fn schnorrsig_sign_helper(
|
|
|
|
&self,
|
|
|
|
msg: &Message,
|
|
|
|
keypair: &KeyPair,
|
|
|
|
nonce_data: *const ffi::types::c_void,
|
2020-12-22 02:41:03 +00:00
|
|
|
) -> Signature {
|
2020-09-15 01:46:19 +00:00
|
|
|
unsafe {
|
|
|
|
let mut sig = [0u8; constants::SCHNORRSIG_SIGNATURE_SIZE];
|
|
|
|
assert_eq!(
|
|
|
|
1,
|
|
|
|
ffi::secp256k1_schnorrsig_sign(
|
|
|
|
self.ctx,
|
|
|
|
sig.as_mut_c_ptr(),
|
|
|
|
msg.as_c_ptr(),
|
|
|
|
keypair.as_ptr(),
|
|
|
|
ffi::secp256k1_nonce_function_bip340,
|
|
|
|
nonce_data
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2020-12-22 02:41:03 +00:00
|
|
|
Signature(sig)
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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"))]
|
2022-01-04 15:55:01 +00:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "rand-std")))]
|
2021-09-09 09:48:13 +00:00
|
|
|
#[deprecated(since = "0.21.0", note = "Use sign_schnorr instead.")]
|
2020-12-22 02:41:03 +00:00
|
|
|
pub fn schnorrsig_sign(&self, msg: &Message, keypair: &KeyPair) -> Signature {
|
2021-09-09 09:48:13 +00:00
|
|
|
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"))]
|
2022-01-04 15:55:01 +00:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "rand-std")))]
|
2021-09-09 09:48:13 +00:00
|
|
|
pub fn sign_schnorr(&self, msg: &Message, keypair: &KeyPair) -> Signature {
|
2020-09-15 01:46:19 +00:00
|
|
|
let mut rng = thread_rng();
|
2021-09-09 09:48:13 +00:00
|
|
|
self.sign_schnorr_with_rng(msg, keypair, &mut rng)
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a schnorr signature without using any auxiliary random data.
|
2021-09-09 09:48:13 +00:00
|
|
|
#[deprecated(since = "0.21.0", note = "Use sign_schnorr_no_aux_rand instead.")]
|
2020-09-15 01:46:19 +00:00
|
|
|
pub fn schnorrsig_sign_no_aux_rand(
|
|
|
|
&self,
|
|
|
|
msg: &Message,
|
|
|
|
keypair: &KeyPair,
|
2021-09-09 09:48:13 +00:00
|
|
|
) -> 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,
|
2020-12-22 02:41:03 +00:00
|
|
|
) -> Signature {
|
2020-09-15 01:46:19 +00:00
|
|
|
self.schnorrsig_sign_helper(msg, keypair, ptr::null())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a Schnorr signature using the given auxiliary random data.
|
2021-09-09 09:48:13 +00:00
|
|
|
#[deprecated(since = "0.21.0", note = "Use sign_schnorr_with_aux_rand instead.")]
|
2020-09-15 01:46:19 +00:00
|
|
|
pub fn schnorrsig_sign_with_aux_rand(
|
|
|
|
&self,
|
|
|
|
msg: &Message,
|
|
|
|
keypair: &KeyPair,
|
|
|
|
aux_rand: &[u8; 32],
|
2021-09-09 09:48:13 +00:00
|
|
|
) -> 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],
|
2020-12-22 02:41:03 +00:00
|
|
|
) -> Signature {
|
2020-09-15 01:46:19 +00:00
|
|
|
self.schnorrsig_sign_helper(
|
|
|
|
msg,
|
|
|
|
keypair,
|
|
|
|
aux_rand.as_c_ptr() as *const ffi::types::c_void,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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"))]
|
2022-01-04 15:55:01 +00:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
|
2021-09-09 09:48:13 +00:00
|
|
|
#[deprecated(since = "0.21.0", note = "Use sign_schnorr_with_rng instead.")]
|
2020-09-15 01:46:19 +00:00
|
|
|
pub fn schnorrsig_sign_with_rng<R: Rng + CryptoRng>(
|
|
|
|
&self,
|
|
|
|
msg: &Message,
|
|
|
|
keypair: &KeyPair,
|
|
|
|
rng: &mut R,
|
2021-09-09 09:48:13 +00:00
|
|
|
) -> 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"))]
|
2022-01-04 15:55:01 +00:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
|
2021-09-09 09:48:13 +00:00
|
|
|
pub fn sign_schnorr_with_rng<R: Rng + CryptoRng>(
|
|
|
|
&self,
|
|
|
|
msg: &Message,
|
|
|
|
keypair: &KeyPair,
|
|
|
|
rng: &mut R,
|
2020-12-22 02:41:03 +00:00
|
|
|
) -> Signature {
|
2020-09-15 01:46:19 +00:00
|
|
|
let mut aux = [0u8; 32];
|
|
|
|
rng.fill_bytes(&mut aux);
|
|
|
|
self.schnorrsig_sign_helper(msg, keypair, aux.as_c_ptr() as *const ffi::types::c_void)
|
|
|
|
}
|
2021-12-23 19:16:33 +00:00
|
|
|
}
|
2020-09-15 01:46:19 +00:00
|
|
|
|
2021-12-23 19:16:33 +00:00
|
|
|
impl<C: Verification> Secp256k1<C> {
|
2020-09-15 01:46:19 +00:00
|
|
|
/// Verify a Schnorr signature.
|
2021-09-09 09:48:13 +00:00
|
|
|
#[deprecated(since = "0.21.0", note = "Use verify_schnorr instead.")]
|
2020-09-15 01:46:19 +00:00
|
|
|
pub fn schnorrsig_verify(
|
|
|
|
&self,
|
|
|
|
sig: &Signature,
|
|
|
|
msg: &Message,
|
2021-09-09 09:37:31 +00:00
|
|
|
pubkey: &XOnlyPublicKey,
|
2021-09-09 09:48:13 +00:00
|
|
|
) -> Result<(), Error> {
|
|
|
|
self.verify_schnorr(sig, msg, pubkey)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Verify a Schnorr signature.
|
|
|
|
pub fn verify_schnorr(
|
|
|
|
&self,
|
|
|
|
sig: &Signature,
|
|
|
|
msg: &Message,
|
|
|
|
pubkey: &XOnlyPublicKey,
|
2020-09-15 01:46:19 +00:00
|
|
|
) -> Result<(), Error> {
|
|
|
|
unsafe {
|
|
|
|
let ret = ffi::secp256k1_schnorrsig_verify(
|
|
|
|
self.ctx,
|
|
|
|
sig.as_c_ptr(),
|
|
|
|
msg.as_c_ptr(),
|
|
|
|
pubkey.as_c_ptr(),
|
|
|
|
);
|
|
|
|
|
2020-12-22 02:38:02 +00:00
|
|
|
if ret == 1 {
|
2020-09-15 01:46:19 +00:00
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(Error::InvalidSignature)
|
2020-12-22 02:38:02 +00:00
|
|
|
}
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-23 19:16:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl <C: Signing> Secp256k1<C> {
|
2022-01-12 07:01:02 +00:00
|
|
|
/// Generates a random Schnorr `KeyPair` and its associated Schnorr `XOnlyPublicKey`.
|
|
|
|
///
|
|
|
|
/// Convenience function for [KeyPair::new] and [KeyPair::public_key].
|
|
|
|
/// Requires a signing-capable context and requires compilation with the "rand" feature.
|
2020-09-15 01:46:19 +00:00
|
|
|
#[inline]
|
|
|
|
#[cfg(any(test, feature = "rand"))]
|
2022-01-04 15:55:01 +00:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
|
2022-01-12 07:01:02 +00:00
|
|
|
#[deprecated(since = "0.21.0", note = "Use kp = KeyPair::new() and kp.public_key()")]
|
2020-09-15 01:46:19 +00:00
|
|
|
pub fn generate_schnorrsig_keypair<R: Rng + ?Sized>(
|
|
|
|
&self,
|
|
|
|
rng: &mut R,
|
2021-09-09 09:37:31 +00:00
|
|
|
) -> (KeyPair, XOnlyPublicKey) {
|
2020-09-15 01:46:19 +00:00
|
|
|
let sk = KeyPair::new(self, rng);
|
2021-12-23 19:16:33 +00:00
|
|
|
let pubkey = XOnlyPublicKey::from_keypair(&sk);
|
2020-09-15 01:46:19 +00:00
|
|
|
(sk, pubkey)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[allow(unused_imports)]
|
2020-09-15 01:46:19 +00:00
|
|
|
mod tests {
|
|
|
|
use std::iter;
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
2022-02-01 02:43:42 +00:00
|
|
|
use rand::rngs::ThreadRng;
|
|
|
|
use rand::{Error, ErrorKind, RngCore, thread_rng};
|
|
|
|
use rand_core::impls;
|
|
|
|
|
|
|
|
use {constants, Error::InvalidPublicKey, from_hex, Message, Secp256k1, SecretKey};
|
|
|
|
|
|
|
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
|
|
use All;
|
|
|
|
|
2020-12-21 23:27:55 +00:00
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
use wasm_bindgen_test::wasm_bindgen_test as test;
|
|
|
|
|
2022-02-01 02:43:42 +00:00
|
|
|
use super::*;
|
|
|
|
|
2022-02-01 01:49:07 +00:00
|
|
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
2020-09-15 01:46:19 +00:00
|
|
|
macro_rules! hex_32 {
|
|
|
|
($hex:expr) => {{
|
2021-10-17 01:07:51 +00:00
|
|
|
let mut result = [0u8; 32];
|
2020-09-15 01:46:19 +00:00
|
|
|
from_hex($hex, &mut result).expect("valid hex string");
|
|
|
|
result
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(all(feature = "rand-std", any(feature = "alloc", feature = "std")))]
|
2020-09-15 01:46:19 +00:00
|
|
|
fn test_schnorrsig_sign_with_aux_rand_verify() {
|
|
|
|
test_schnorrsig_sign_helper(|secp, msg, seckey, rng| {
|
2021-10-17 01:07:51 +00:00
|
|
|
let mut aux_rand = [0u8; 32];
|
2020-09-15 01:46:19 +00:00
|
|
|
rng.fill_bytes(&mut aux_rand);
|
2021-09-09 09:48:13 +00:00
|
|
|
secp.sign_schnorr_with_aux_rand(msg, seckey, &aux_rand)
|
2020-09-15 01:46:19 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(all(feature = "rand-std", any(feature = "alloc", feature = "std")))]
|
2020-09-15 01:46:19 +00:00
|
|
|
fn test_schnorrsig_sign_with_rng_verify() {
|
|
|
|
test_schnorrsig_sign_helper(|secp, msg, seckey, mut rng| {
|
2021-09-09 09:48:13 +00:00
|
|
|
secp.sign_schnorr_with_rng(msg, seckey, &mut rng)
|
2020-09-15 01:46:19 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(all(feature = "rand-std", any(feature = "alloc", feature = "std")))]
|
2020-09-15 01:46:19 +00:00
|
|
|
fn test_schnorrsig_sign_verify() {
|
|
|
|
test_schnorrsig_sign_helper(|secp, msg, seckey, _| {
|
2021-09-09 09:48:13 +00:00
|
|
|
secp.sign_schnorr(msg, seckey)
|
2020-09-15 01:46:19 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(all(feature = "rand-std", any(feature = "alloc", feature = "std")))]
|
2020-09-15 01:46:19 +00:00
|
|
|
fn test_schnorrsig_sign_no_aux_rand_verify() {
|
|
|
|
test_schnorrsig_sign_helper(|secp, msg, seckey, _| {
|
2021-09-09 09:48:13 +00:00
|
|
|
secp.sign_schnorr_no_aux_rand(msg, seckey)
|
2020-09-15 01:46:19 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(all(feature = "rand-std", any(feature = "alloc", feature = "std")))]
|
2021-09-09 10:01:59 +00:00
|
|
|
fn test_schnorrsig_sign_helper(
|
|
|
|
sign: fn(&Secp256k1<All>, &Message, &KeyPair, &mut ThreadRng) -> Signature,
|
|
|
|
) {
|
|
|
|
let secp = Secp256k1::new();
|
|
|
|
|
|
|
|
let mut rng = thread_rng();
|
2022-01-12 07:01:02 +00:00
|
|
|
let kp = KeyPair::new(&secp, &mut rng);
|
|
|
|
let pk = kp.public_key();
|
|
|
|
|
2021-09-09 10:01:59 +00:00
|
|
|
let mut msg = [0u8; 32];
|
|
|
|
|
|
|
|
for _ in 0..100 {
|
|
|
|
rng.fill_bytes(&mut msg);
|
|
|
|
let msg = Message::from_slice(&msg).unwrap();
|
|
|
|
|
2022-01-12 07:01:02 +00:00
|
|
|
let sig = sign(&secp, &msg, &kp, &mut rng);
|
2021-09-09 10:01:59 +00:00
|
|
|
|
2022-01-12 07:01:02 +00:00
|
|
|
assert!(secp.verify_schnorr(&sig, &msg, &pk).is_ok());
|
2021-09-09 10:01:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-15 01:46:19 +00:00
|
|
|
#[test]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
2021-01-11 19:14:42 +00:00
|
|
|
#[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs
|
2020-09-15 01:46:19 +00:00
|
|
|
fn test_schnorrsig_sign() {
|
|
|
|
let secp = Secp256k1::new();
|
|
|
|
|
|
|
|
let hex_msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614");
|
|
|
|
let msg = Message::from_slice(&hex_msg).unwrap();
|
|
|
|
let sk = KeyPair::from_seckey_str(
|
|
|
|
&secp,
|
|
|
|
"688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF",
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let aux_rand: [u8; 32] =
|
|
|
|
hex_32!("02CCE08E913F22A36C5648D6405A2C7C50106E7AA2F1649E381C7F09D16B80AB");
|
|
|
|
let expected_sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap();
|
|
|
|
|
|
|
|
let sig = secp
|
2021-09-09 09:48:13 +00:00
|
|
|
.sign_schnorr_with_aux_rand(&msg, &sk, &aux_rand);
|
2020-09-15 01:46:19 +00:00
|
|
|
|
|
|
|
assert_eq!(expected_sig, sig);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-01-11 19:14:42 +00:00
|
|
|
#[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
2020-09-15 01:46:19 +00:00
|
|
|
fn test_schnorrsig_verify() {
|
|
|
|
let secp = Secp256k1::new();
|
|
|
|
|
|
|
|
let hex_msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614");
|
|
|
|
let msg = Message::from_slice(&hex_msg).unwrap();
|
|
|
|
let sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap();
|
|
|
|
let pubkey =
|
2021-09-09 09:37:31 +00:00
|
|
|
XOnlyPublicKey::from_str("B33CC9EDC096D0A83416964BD3C6247B8FECD256E4EFA7870D2C854BDEB33390")
|
2020-09-15 01:46:19 +00:00
|
|
|
.unwrap();
|
|
|
|
|
2021-09-09 09:48:13 +00:00
|
|
|
assert!(secp.verify_schnorr(&sig, &msg, &pubkey).is_ok());
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-06-16 08:56:59 +00:00
|
|
|
fn test_pubkey_from_slice() {
|
2021-09-09 09:37:31 +00:00
|
|
|
assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey));
|
|
|
|
assert_eq!(XOnlyPublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey));
|
|
|
|
let pk = XOnlyPublicKey::from_slice(&[
|
2020-09-15 01:46:19 +00:00
|
|
|
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,
|
|
|
|
0xDE, 0xB3, 0x33, 0x90,
|
|
|
|
]);
|
|
|
|
assert!(pk.is_ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
2021-06-16 08:56:59 +00:00
|
|
|
fn test_pubkey_serialize_roundtrip() {
|
2020-09-15 01:46:19 +00:00
|
|
|
let secp = Secp256k1::new();
|
2022-01-12 07:01:02 +00:00
|
|
|
let kp = KeyPair::new(&secp, &mut thread_rng());
|
|
|
|
let pk = kp.public_key();
|
|
|
|
|
|
|
|
let ser = pk.serialize();
|
2021-09-09 09:37:31 +00:00
|
|
|
let pubkey2 = XOnlyPublicKey::from_slice(&ser).unwrap();
|
2022-01-12 07:01:02 +00:00
|
|
|
assert_eq!(pk, pubkey2);
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
|
2021-06-16 08:56:59 +00:00
|
|
|
#[test]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
2021-06-16 08:56:59 +00:00
|
|
|
fn test_xonly_key_extraction() {
|
|
|
|
let secp = Secp256k1::new();
|
|
|
|
let sk_str = "688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF";
|
|
|
|
let keypair = KeyPair::from_seckey_str(&secp, sk_str).unwrap();
|
2021-06-20 15:07:44 +00:00
|
|
|
let sk = SecretKey::from_keypair(&keypair);
|
2021-06-16 08:56:59 +00:00
|
|
|
assert_eq!(SecretKey::from_str(sk_str).unwrap(), sk);
|
2021-06-20 15:07:44 +00:00
|
|
|
let pk = ::key::PublicKey::from_keypair(&keypair);
|
2021-06-16 08:56:59 +00:00
|
|
|
assert_eq!(::key::PublicKey::from_secret_key(&secp, &sk), pk);
|
2022-01-12 07:01:02 +00:00
|
|
|
let xpk = keypair.public_key();
|
2021-09-09 09:37:31 +00:00
|
|
|
assert_eq!(XOnlyPublicKey::from(pk), xpk);
|
2021-06-16 08:56:59 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 01:46:19 +00:00
|
|
|
#[test]
|
|
|
|
fn test_pubkey_from_bad_slice() {
|
|
|
|
// Bad sizes
|
|
|
|
assert_eq!(
|
2021-09-09 09:37:31 +00:00
|
|
|
XOnlyPublicKey::from_slice(&[0; constants::SCHNORRSIG_PUBLIC_KEY_SIZE - 1]),
|
2020-09-15 01:46:19 +00:00
|
|
|
Err(InvalidPublicKey)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2021-09-09 09:37:31 +00:00
|
|
|
XOnlyPublicKey::from_slice(&[0; constants::SCHNORRSIG_PUBLIC_KEY_SIZE + 1]),
|
2020-09-15 01:46:19 +00:00
|
|
|
Err(InvalidPublicKey)
|
|
|
|
);
|
|
|
|
|
|
|
|
// Bad parse
|
|
|
|
assert_eq!(
|
2021-09-09 09:37:31 +00:00
|
|
|
XOnlyPublicKey::from_slice(&[0xff; constants::SCHNORRSIG_PUBLIC_KEY_SIZE]),
|
2020-09-15 01:46:19 +00:00
|
|
|
Err(InvalidPublicKey)
|
|
|
|
);
|
2021-02-18 14:50:58 +00:00
|
|
|
// In fuzzing mode restrictions on public key validity are much more
|
|
|
|
// relaxed, thus the invalid check below is expected to fail.
|
|
|
|
#[cfg(not(fuzzing))]
|
2020-09-15 01:46:19 +00:00
|
|
|
assert_eq!(
|
2021-09-09 09:37:31 +00:00
|
|
|
XOnlyPublicKey::from_slice(&[0x55; constants::SCHNORRSIG_PUBLIC_KEY_SIZE]),
|
2020-09-15 01:46:19 +00:00
|
|
|
Err(InvalidPublicKey)
|
|
|
|
);
|
2021-09-09 09:37:31 +00:00
|
|
|
assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey));
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(feature = "std")]
|
2020-09-15 01:46:19 +00:00
|
|
|
fn test_pubkey_display_output() {
|
2021-02-18 14:50:58 +00:00
|
|
|
#[cfg(not(fuzzing))]
|
2022-02-01 01:49:07 +00:00
|
|
|
let pk = {
|
|
|
|
let secp = Secp256k1::new();
|
|
|
|
static SK_BYTES: [u8; 32] = [
|
|
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
|
|
|
0x06, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63,
|
|
|
|
0x63, 0x63, 0x63, 0x63,
|
|
|
|
];
|
|
|
|
|
|
|
|
let kp = KeyPair::from_seckey_slice(&secp, &SK_BYTES).expect("sk");
|
|
|
|
|
|
|
|
// In fuzzing mode secret->public key derivation is different, so
|
2022-02-02 21:36:36 +00:00
|
|
|
// hard-code the expected result.
|
2022-02-01 01:49:07 +00:00
|
|
|
kp.public_key()
|
|
|
|
};
|
2021-02-18 14:50:58 +00:00
|
|
|
#[cfg(fuzzing)]
|
2021-09-09 09:37:31 +00:00
|
|
|
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");
|
2020-09-15 01:46:19 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
pk.to_string(),
|
|
|
|
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2021-09-09 09:37:31 +00:00
|
|
|
XOnlyPublicKey::from_str("18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166")
|
2020-09-15 01:46:19 +00:00
|
|
|
.unwrap(),
|
|
|
|
pk
|
|
|
|
);
|
|
|
|
|
2021-09-09 09:37:31 +00:00
|
|
|
assert!(XOnlyPublicKey::from_str(
|
2020-09-15 01:46:19 +00:00
|
|
|
"00000000000000000000000000000000000000000000000000000000000000000"
|
|
|
|
)
|
|
|
|
.is_err());
|
2021-09-09 09:37:31 +00:00
|
|
|
assert!(XOnlyPublicKey::from_str(
|
2020-09-15 01:46:19 +00:00
|
|
|
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16601"
|
|
|
|
)
|
|
|
|
.is_err());
|
2021-09-09 09:37:31 +00:00
|
|
|
assert!(XOnlyPublicKey::from_str(
|
2020-09-15 01:46:19 +00:00
|
|
|
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16"
|
|
|
|
)
|
|
|
|
.is_err());
|
2021-09-09 09:37:31 +00:00
|
|
|
assert!(XOnlyPublicKey::from_str(
|
2020-09-15 01:46:19 +00:00
|
|
|
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1"
|
|
|
|
)
|
|
|
|
.is_err());
|
2021-09-09 09:37:31 +00:00
|
|
|
assert!(XOnlyPublicKey::from_str(
|
2020-09-15 01:46:19 +00:00
|
|
|
"xx18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1"
|
|
|
|
)
|
|
|
|
.is_err());
|
|
|
|
|
|
|
|
let long_str: String = iter::repeat('a').take(1024 * 1024).collect();
|
2021-09-09 09:37:31 +00:00
|
|
|
assert!(XOnlyPublicKey::from_str(&long_str).is_err());
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-02-18 14:50:58 +00:00
|
|
|
// In fuzzing mode secret->public key derivation is different, so
|
|
|
|
// this test will never correctly derive the static pubkey.
|
|
|
|
#[cfg(not(fuzzing))]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))]
|
2020-09-15 01:46:19 +00:00
|
|
|
fn test_pubkey_serialize() {
|
|
|
|
struct DumbRng(u32);
|
|
|
|
impl RngCore for DumbRng {
|
|
|
|
fn next_u32(&mut self) -> u32 {
|
|
|
|
self.0 = self.0.wrapping_add(1);
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
fn next_u64(&mut self) -> u64 {
|
|
|
|
self.next_u32() as u64
|
|
|
|
}
|
|
|
|
fn try_fill_bytes(&mut self, _dest: &mut [u8]) -> Result<(), Error> {
|
|
|
|
Err(Error::new(ErrorKind::Unavailable, "not implemented"))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
|
|
|
impls::fill_bytes_via_next(self, dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-12 07:01:02 +00:00
|
|
|
let secp = Secp256k1::new();
|
|
|
|
let kp = KeyPair::new(&secp, &mut DumbRng(0));
|
|
|
|
let pk = kp.public_key();
|
2020-09-15 01:46:19 +00:00
|
|
|
assert_eq!(
|
2022-01-12 07:01:02 +00:00
|
|
|
&pk.serialize()[..],
|
2020-09-15 01:46:19 +00:00
|
|
|
&[
|
|
|
|
124, 121, 49, 14, 253, 63, 197, 50, 39, 194, 107, 17, 193, 219, 108, 154, 126, 9,
|
|
|
|
181, 248, 2, 12, 149, 233, 198, 71, 149, 134, 250, 184, 154, 229
|
|
|
|
][..]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-01-11 19:14:42 +00:00
|
|
|
#[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs
|
2020-09-15 01:46:19 +00:00
|
|
|
#[test]
|
2022-02-01 02:43:42 +00:00
|
|
|
#[cfg(all(feature = "serde", any(feature = "alloc", feature = "std")))]
|
2021-01-12 00:50:52 +00:00
|
|
|
fn test_serde() {
|
2020-09-15 01:46:19 +00:00
|
|
|
use serde_test::{assert_tokens, Configure, Token};
|
|
|
|
|
|
|
|
let s = Secp256k1::new();
|
|
|
|
|
|
|
|
let msg = Message::from_slice(&[1; 32]).unwrap();
|
|
|
|
let keypair = KeyPair::from_seckey_slice(&s, &[2; 32]).unwrap();
|
2021-10-17 01:07:51 +00:00
|
|
|
let aux = [3u8; 32];
|
2020-09-15 01:46:19 +00:00
|
|
|
let sig = s
|
2021-09-09 09:48:13 +00:00
|
|
|
.sign_schnorr_with_aux_rand(&msg, &keypair, &aux);
|
2020-09-15 01:46:19 +00:00
|
|
|
static SIG_BYTES: [u8; constants::SCHNORRSIG_SIGNATURE_SIZE] = [
|
|
|
|
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,
|
|
|
|
0x2c, 0x26, 0x70, 0x6f, 0x1e, 0xeb, 0x43, 0x2b, 0x3d, 0xba, 0x9a, 0x01, 0x08, 0x2f,
|
|
|
|
0x9e, 0x4d, 0x4e, 0xf5, 0x67, 0x8a, 0xd0, 0xd9, 0xd5, 0x32, 0xc0, 0xdf, 0xa9, 0x07,
|
|
|
|
0xb5, 0x68, 0x72, 0x2d, 0x0b, 0x01, 0x19, 0xba,
|
|
|
|
];
|
|
|
|
static SIG_STR: &'static str = "\
|
|
|
|
14d0bf1a8953506fb460f58be141af767fd112535fb3922ef217308e2c26706f1eeb432b3dba9a01082f9e4d4ef5678ad0d9d532c0dfa907b568722d0b0119ba\
|
|
|
|
";
|
|
|
|
|
2021-01-12 00:50:52 +00:00
|
|
|
static PK_BYTES: [u8; 32] = [
|
|
|
|
24, 132, 87, 129, 246, 49, 196, 143, 28, 151, 9, 226, 48, 146, 6, 125, 6, 131, 127,
|
|
|
|
48, 170, 12, 208, 84, 74, 200, 135, 254, 145, 221, 209, 102
|
|
|
|
];
|
|
|
|
static PK_STR: &'static str = "\
|
|
|
|
18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\
|
|
|
|
";
|
2021-09-09 09:37:31 +00:00
|
|
|
let pk = XOnlyPublicKey::from_slice(&PK_BYTES).unwrap();
|
2021-01-12 00:50:52 +00:00
|
|
|
|
2020-09-15 01:46:19 +00:00
|
|
|
assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]);
|
2021-01-12 00:50:52 +00:00
|
|
|
assert_tokens(&sig.compact(), &[Token::Bytes(&SIG_BYTES[..])]);
|
|
|
|
assert_tokens(&sig.compact(), &[Token::ByteBuf(&SIG_BYTES[..])]);
|
|
|
|
|
2020-09-15 01:46:19 +00:00
|
|
|
assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]);
|
2021-01-12 00:50:52 +00:00
|
|
|
assert_tokens(&sig.readable(), &[Token::Str(SIG_STR)]);
|
|
|
|
assert_tokens(&sig.readable(), &[Token::String(SIG_STR)]);
|
|
|
|
|
|
|
|
assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]);
|
|
|
|
assert_tokens(&pk.compact(), &[Token::Bytes(&PK_BYTES[..])]);
|
|
|
|
assert_tokens(&pk.compact(), &[Token::ByteBuf(&PK_BYTES[..])]);
|
|
|
|
|
|
|
|
assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]);
|
|
|
|
assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]);
|
|
|
|
assert_tokens(&pk.readable(), &[Token::String(PK_STR)]);
|
2020-09-15 01:46:19 +00:00
|
|
|
}
|
|
|
|
}
|