Add schnorrsig module
This commit is contained in:
parent
47b33828bc
commit
09b04560bc
|
@ -34,6 +34,15 @@ pub const MAX_SIGNATURE_SIZE: usize = 72;
|
|||
/// The maximum size of a compact signature
|
||||
pub const COMPACT_SIGNATURE_SIZE: usize = 64;
|
||||
|
||||
/// Size of a Schnorr signature
|
||||
pub const SCHNORRSIG_SIGNATURE_SIZE: usize = 64;
|
||||
|
||||
/// Size of a Schnorr public key
|
||||
pub const SCHNORRSIG_PUBLIC_KEY_SIZE: usize = 32;
|
||||
|
||||
/// Size of a key pair
|
||||
pub const KEY_PAIR_SIZE: usize = 96;
|
||||
|
||||
/// The Prime for the secp256k1 field element.
|
||||
pub const FIELD_SIZE: [u8; 32] = [
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
|
|
@ -142,6 +142,7 @@ mod context;
|
|||
pub mod constants;
|
||||
pub mod ecdh;
|
||||
pub mod key;
|
||||
pub mod schnorrsig;
|
||||
#[cfg(feature = "recovery")]
|
||||
pub mod recovery;
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ macro_rules! serde_impl(
|
|||
|
||||
if d.is_human_readable() {
|
||||
let sl: &str = ::serde::Deserialize::deserialize(d)?;
|
||||
SecretKey::from_str(sl).map_err(D::Error::custom)
|
||||
$t::from_str(sl).map_err(D::Error::custom)
|
||||
} else {
|
||||
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?;
|
||||
if sl.len() != $len {
|
||||
|
|
|
@ -0,0 +1,710 @@
|
|||
//! # 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::Error::{InvalidPublicKey, InvalidSecretKey, InvalidSignature};
|
||||
use super::{from_hex, Error};
|
||||
use core::{fmt, ptr, str};
|
||||
use ffi::{self, CPtr};
|
||||
use {constants, Secp256k1};
|
||||
use {Message, Signing, Verification};
|
||||
|
||||
/// 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);
|
||||
serde_impl!(Signature, constants::SCHNORRSIG_SIGNATURE_SIZE);
|
||||
|
||||
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> {
|
||||
let mut res = [0; constants::SCHNORRSIG_SIGNATURE_SIZE];
|
||||
match from_hex(s, &mut res) {
|
||||
Ok(constants::SCHNORRSIG_SIGNATURE_SIZE) => {
|
||||
Signature::from_slice(&res[0..constants::SCHNORRSIG_SIGNATURE_SIZE])
|
||||
}
|
||||
_ => Err(Error::InvalidSignature),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Opaque data structure that holds a keypair consisting of a secret and a public key.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
|
||||
pub struct KeyPair(ffi::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 = [0; 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(InvalidPublicKey),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 => {
|
||||
let mut ret = [0; constants::SCHNORRSIG_SIGNATURE_SIZE];
|
||||
ret[..].copy_from_slice(data);
|
||||
Ok(Signature(ret))
|
||||
}
|
||||
_ => Err(InvalidSignature),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyPair {
|
||||
/// Obtains a raw const pointer suitable for use with FFI functions
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const ffi::KeyPair {
|
||||
&self.0 as *const _
|
||||
}
|
||||
|
||||
/// 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 as *mut _
|
||||
}
|
||||
|
||||
/// Creates a Schnorr KeyPair directly from a secret key slice
|
||||
#[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(InvalidPublicKey);
|
||||
}
|
||||
|
||||
let mut kp = ffi::KeyPair::new();
|
||||
unsafe {
|
||||
if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, data.as_c_ptr()) == 1 {
|
||||
Ok(KeyPair(kp))
|
||||
} else {
|
||||
Err(InvalidSecretKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a Schnorr KeyPair directly from a secret key string
|
||||
#[inline]
|
||||
pub fn from_seckey_str<C: Signing>(secp: &Secp256k1<C>, s: &str) -> Result<KeyPair, Error> {
|
||||
let mut res = [0; 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(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();
|
||||
let mut keypair = ffi::KeyPair::new();
|
||||
unsafe {
|
||||
while ffi::secp256k1_keypair_create(secp.ctx, &mut keypair, data.as_c_ptr()) == 0 {
|
||||
data = random_32_bytes();
|
||||
}
|
||||
}
|
||||
KeyPair(keypair)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[inline]
|
||||
pub fn 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 as *mut _,
|
||||
tweak.as_c_ptr(),
|
||||
);
|
||||
|
||||
return 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 as *const _
|
||||
}
|
||||
|
||||
/// 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 as *mut _
|
||||
}
|
||||
|
||||
/// 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 xonly_pk = ffi::XOnlyPublicKey::new();
|
||||
let mut pk_parity = 0;
|
||||
unsafe {
|
||||
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
|
||||
#[inline]
|
||||
pub fn from_slice(data: &[u8]) -> Result<PublicKey, Error> {
|
||||
if data.is_empty() || data.len() != constants::SCHNORRSIG_PUBLIC_KEY_SIZE {
|
||||
return Err(InvalidPublicKey);
|
||||
}
|
||||
|
||||
let mut pk = ffi::XOnlyPublicKey::new();
|
||||
unsafe {
|
||||
if ffi::secp256k1_xonly_pubkey_parse(
|
||||
ffi::secp256k1_context_no_precomp,
|
||||
&mut pk,
|
||||
data.as_c_ptr(),
|
||||
) == 1
|
||||
{
|
||||
Ok(PublicKey(pk))
|
||||
} else {
|
||||
Err(InvalidPublicKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Serialize the key as a byte-encoded pair of values. In compressed form
|
||||
/// the y-coordinate is represented by only a single bit, as x determines
|
||||
/// it up to one bit.
|
||||
pub fn serialize(&self) -> [u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE] {
|
||||
let mut ret = [0; 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 a schnorrsig PublicKey by adding the generator multiplied with the given tweak to it.
|
||||
/// Will return an error if the resulting key would be invalid or if
|
||||
/// the tweak was not a 32-byte length slice.
|
||||
pub fn add_assign<V: Verification>(
|
||||
&mut self,
|
||||
secp: &Secp256k1<V>,
|
||||
tweak: &[u8],
|
||||
) -> Result<(), 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);
|
||||
}
|
||||
|
||||
err = ffi::secp256k1_xonly_pubkey_from_pubkey(
|
||||
secp.ctx,
|
||||
&mut self.0 as *mut _,
|
||||
ptr::null_mut(),
|
||||
&pubkey,
|
||||
);
|
||||
|
||||
return if err == 0 {
|
||||
Err(Error::InvalidPublicKey)
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
serde_impl_from_slice!(PublicKey);
|
||||
|
||||
impl<C: Signing> Secp256k1<C> {
|
||||
fn schnorrsig_sign_helper(
|
||||
&self,
|
||||
msg: &Message,
|
||||
keypair: &KeyPair,
|
||||
nonce_data: *const ffi::types::c_void,
|
||||
) -> Result<Signature, Error> {
|
||||
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
|
||||
)
|
||||
);
|
||||
|
||||
Ok(Signature(sig))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 schnorrsig_sign(&self, msg: &Message, keypair: &KeyPair) -> Result<Signature, Error> {
|
||||
let mut rng = thread_rng();
|
||||
self.schnorrsig_sign_with_rng(msg, keypair, &mut rng)
|
||||
}
|
||||
|
||||
/// Create a schnorr signature without using any auxiliary random data.
|
||||
pub fn schnorrsig_sign_no_aux_rand(
|
||||
&self,
|
||||
msg: &Message,
|
||||
keypair: &KeyPair,
|
||||
) -> Result<Signature, Error> {
|
||||
self.schnorrsig_sign_helper(msg, keypair, ptr::null())
|
||||
}
|
||||
|
||||
/// Create a Schnorr signature using the given auxiliary random data.
|
||||
pub fn schnorrsig_sign_with_aux_rand(
|
||||
&self,
|
||||
msg: &Message,
|
||||
keypair: &KeyPair,
|
||||
aux_rand: &[u8; 32],
|
||||
) -> Result<Signature, Error> {
|
||||
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"))]
|
||||
pub fn schnorrsig_sign_with_rng<R: Rng + CryptoRng>(
|
||||
&self,
|
||||
msg: &Message,
|
||||
keypair: &KeyPair,
|
||||
rng: &mut R,
|
||||
) -> Result<Signature, Error> {
|
||||
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)
|
||||
}
|
||||
|
||||
/// Verify a Schnorr signature.
|
||||
pub fn schnorrsig_verify(
|
||||
&self,
|
||||
sig: &Signature,
|
||||
msg: &Message,
|
||||
pubkey: &PublicKey,
|
||||
) -> Result<(), Error> {
|
||||
unsafe {
|
||||
let ret = ffi::secp256k1_schnorrsig_verify(
|
||||
self.ctx,
|
||||
sig.as_c_ptr(),
|
||||
msg.as_c_ptr(),
|
||||
pubkey.as_c_ptr(),
|
||||
);
|
||||
|
||||
return if ret == 1 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::InvalidSignature)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a random Schnorr KeyPair and its associated Schnorr PublicKey.
|
||||
/// Convenience function for `schnorrsig::KeyPair::new` and
|
||||
/// `schnorrsig::PublicKey::from_keypair`; call those functions directly for
|
||||
/// batch key generation. Requires a signing-capable context. Requires compilation
|
||||
/// with the "rand" feature.
|
||||
#[inline]
|
||||
#[cfg(any(test, feature = "rand"))]
|
||||
pub fn generate_schnorrsig_keypair<R: Rng + ?Sized>(
|
||||
&self,
|
||||
rng: &mut R,
|
||||
) -> (KeyPair, PublicKey) {
|
||||
let sk = KeyPair::new(self, rng);
|
||||
let pubkey = PublicKey::from_keypair(self, &sk);
|
||||
(sk, pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::Error::InvalidPublicKey;
|
||||
use super::super::{constants, from_hex, All, Message, Secp256k1};
|
||||
use super::{KeyPair, PublicKey, Signature};
|
||||
use rand::{rngs::ThreadRng, thread_rng, Error, ErrorKind, RngCore};
|
||||
use rand_core::impls;
|
||||
use std::iter;
|
||||
use std::str::FromStr;
|
||||
|
||||
macro_rules! hex_32 {
|
||||
($hex:expr) => {{
|
||||
let mut result = [0; 32];
|
||||
from_hex($hex, &mut result).expect("valid hex string");
|
||||
result
|
||||
}};
|
||||
}
|
||||
|
||||
fn test_schnorrsig_sign_helper(
|
||||
sign: fn(&Secp256k1<All>, &Message, &KeyPair, &mut ThreadRng) -> Signature,
|
||||
) {
|
||||
let secp = Secp256k1::new();
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let (seckey, pubkey) = secp.generate_schnorrsig_keypair(&mut rng);
|
||||
let mut msg = [0; 32];
|
||||
|
||||
for _ in 0..100 {
|
||||
rng.fill_bytes(&mut msg);
|
||||
let msg = Message::from_slice(&msg).unwrap();
|
||||
|
||||
let sig = sign(&secp, &msg, &seckey, &mut rng);
|
||||
|
||||
assert!(secp.schnorrsig_verify(&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 = [0; 32];
|
||||
rng.fill_bytes(&mut aux_rand);
|
||||
secp.schnorrsig_sign_with_aux_rand(msg, seckey, &aux_rand)
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
#[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)
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_schnorrsig_sign_verify() {
|
||||
test_schnorrsig_sign_helper(|secp, msg, seckey, _| {
|
||||
secp.schnorrsig_sign(msg, seckey).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_schnorrsig_sign_no_aux_rand_verify() {
|
||||
test_schnorrsig_sign_helper(|secp, msg, seckey, _| {
|
||||
secp.schnorrsig_sign_no_aux_rand(msg, seckey).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
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
|
||||
.schnorrsig_sign_with_aux_rand(&msg, &sk, &aux_rand)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(expected_sig, sig);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 =
|
||||
PublicKey::from_str("B33CC9EDC096D0A83416964BD3C6247B8FECD256E4EFA7870D2C854BDEB33390")
|
||||
.unwrap();
|
||||
|
||||
assert!(secp.schnorrsig_verify(&sig, &msg, &pubkey).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pubkey_from_slice() {
|
||||
assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey));
|
||||
assert_eq!(PublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey));
|
||||
let pk = PublicKey::from_slice(&[
|
||||
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]
|
||||
fn pubkey_serialize_roundtrip() {
|
||||
let secp = Secp256k1::new();
|
||||
let (_, pubkey) = secp.generate_schnorrsig_keypair(&mut thread_rng());
|
||||
let ser = pubkey.serialize();
|
||||
let pubkey2 = PublicKey::from_slice(&ser).unwrap();
|
||||
assert_eq!(pubkey, pubkey2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pubkey_from_bad_slice() {
|
||||
// Bad sizes
|
||||
assert_eq!(
|
||||
PublicKey::from_slice(&[0; constants::SCHNORRSIG_PUBLIC_KEY_SIZE - 1]),
|
||||
Err(InvalidPublicKey)
|
||||
);
|
||||
assert_eq!(
|
||||
PublicKey::from_slice(&[0; constants::SCHNORRSIG_PUBLIC_KEY_SIZE + 1]),
|
||||
Err(InvalidPublicKey)
|
||||
);
|
||||
|
||||
// Bad parse
|
||||
assert_eq!(
|
||||
PublicKey::from_slice(&[0xff; constants::SCHNORRSIG_PUBLIC_KEY_SIZE]),
|
||||
Err(InvalidPublicKey)
|
||||
);
|
||||
assert_eq!(
|
||||
PublicKey::from_slice(&[0x55; constants::SCHNORRSIG_PUBLIC_KEY_SIZE]),
|
||||
Err(InvalidPublicKey)
|
||||
);
|
||||
assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pubkey_display_output() {
|
||||
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 s = Secp256k1::signing_only();
|
||||
let sk = KeyPair::from_seckey_slice(&secp, &SK_BYTES).expect("sk");
|
||||
let pk = PublicKey::from_keypair(&s, &sk);
|
||||
|
||||
assert_eq!(
|
||||
pk.to_string(),
|
||||
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"
|
||||
);
|
||||
assert_eq!(
|
||||
PublicKey::from_str("18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166")
|
||||
.unwrap(),
|
||||
pk
|
||||
);
|
||||
|
||||
assert!(PublicKey::from_str(
|
||||
"00000000000000000000000000000000000000000000000000000000000000000"
|
||||
)
|
||||
.is_err());
|
||||
assert!(PublicKey::from_str(
|
||||
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16601"
|
||||
)
|
||||
.is_err());
|
||||
assert!(PublicKey::from_str(
|
||||
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16"
|
||||
)
|
||||
.is_err());
|
||||
assert!(PublicKey::from_str(
|
||||
"18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1"
|
||||
)
|
||||
.is_err());
|
||||
assert!(PublicKey::from_str(
|
||||
"xx18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1"
|
||||
)
|
||||
.is_err());
|
||||
|
||||
let long_str: String = iter::repeat('a').take(1024 * 1024).collect();
|
||||
assert!(PublicKey::from_str(&long_str).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
let s = Secp256k1::new();
|
||||
let (_, pubkey) = s.generate_schnorrsig_keypair(&mut DumbRng(0));
|
||||
assert_eq!(
|
||||
&pubkey.serialize()[..],
|
||||
&[
|
||||
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
|
||||
][..]
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
fn test_signature_serde() {
|
||||
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();
|
||||
let aux = [3; 32];
|
||||
let sig = s
|
||||
.schnorrsig_sign_with_aux_rand(&msg, &keypair, &aux)
|
||||
.unwrap();
|
||||
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\
|
||||
";
|
||||
|
||||
assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]);
|
||||
assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]);
|
||||
}
|
||||
#[test]
|
||||
fn test_addition() {
|
||||
let s = Secp256k1::new();
|
||||
|
||||
for _ in 0..10 {
|
||||
let mut tweak = [0u8; 32];
|
||||
thread_rng().fill_bytes(&mut tweak);
|
||||
let (mut kp, mut pk) = s.generate_schnorrsig_keypair(&mut thread_rng());
|
||||
kp.add_assign(&s, &tweak).expect("Tweak error");
|
||||
pk.add_assign(&s, &tweak).expect("Tweak error");
|
||||
assert_eq!(PublicKey::from_keypair(&s, &kp), pk);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue