1use crate::Error;
5use bitcoin::hashes::{sha256t_hash_newtype, Hash};
6use core::ptr;
7use secp256k1_sys::{
8 types::{c_int, c_uchar, c_void, size_t},
9 CPtr, SchnorrSigExtraParams,
10};
11use secp256k1_zkp::{
12 schnorr::Signature as SchnorrSignature, Keypair, Message, PublicKey, Scalar, Secp256k1,
13 Signing, Verification, XOnlyPublicKey,
14};
15
16const BIP340_MIDSTATE: [u8; 32] = [
17 0x9c, 0xec, 0xba, 0x11, 0x23, 0x92, 0x53, 0x81, 0x11, 0x67, 0x91, 0x12, 0xd1, 0x62, 0x7e, 0x0f,
18 0x97, 0xc8, 0x75, 0x50, 0x00, 0x3c, 0xc7, 0x65, 0x90, 0xf6, 0x11, 0x64, 0x33, 0xe9, 0xb6, 0x6a,
19];
20
21sha256t_hash_newtype! {
22 pub struct BIP340HashTag = raw(BIP340_MIDSTATE, 64);
24
25 #[hash_newtype(backward)]
27 pub struct BIP340Hash(_);
28}
29
30pub fn schnorrsig_sign_with_nonce<S: Signing>(
32 secp: &Secp256k1<S>,
33 msg: &Message,
34 keypair: &Keypair,
35 nonce: &[u8; 32],
36) -> SchnorrSignature {
37 unsafe {
38 let mut sig = [0u8; secp256k1_zkp::constants::SCHNORR_SIGNATURE_SIZE];
39 let extra_params =
40 SchnorrSigExtraParams::new(Some(constant_nonce_fn), nonce.as_c_ptr() as *const c_void);
41 assert_eq!(
42 1,
43 secp256k1_sys::secp256k1_schnorrsig_sign_custom(
44 secp.ctx().as_ref(),
45 sig.as_mut_c_ptr(),
46 msg.as_c_ptr(),
47 32_usize,
48 keypair.as_c_ptr(),
49 &extra_params,
50 )
51 );
52
53 SchnorrSignature::from_slice(&sig).unwrap()
54 }
55}
56
57pub fn schnorrsig_compute_sig_point<C: Verification>(
59 secp: &Secp256k1<C>,
60 pubkey: &XOnlyPublicKey,
61 nonce: &XOnlyPublicKey,
62 message: &Message,
63) -> Result<PublicKey, Error> {
64 let hash = create_schnorr_hash(message, nonce, pubkey);
65 let pk = schnorr_pubkey_to_pubkey(pubkey)?;
66 let scalar = Scalar::from_be_bytes(hash).unwrap();
67 let tweaked = pk.mul_tweak(secp, &scalar)?;
68 let npk = schnorr_pubkey_to_pubkey(nonce)?;
69 Ok(npk.combine(&tweaked)?)
70}
71
72pub fn schnorrsig_decompose(
74 signature: &SchnorrSignature,
75) -> Result<(XOnlyPublicKey, &[u8]), Error> {
76 let bytes = signature.as_ref();
77 Ok((XOnlyPublicKey::from_slice(&bytes[0..32])?, &bytes[32..64]))
78}
79
80extern "C" fn constant_nonce_fn(
81 nonce32: *mut c_uchar,
82 _msg32: *const c_uchar,
83 _msg_len: size_t,
84 _key32: *const c_uchar,
85 _xonly_pk32: *const c_uchar,
86 _algo16: *const c_uchar,
87 _algo_len: size_t,
88 data: *mut c_void,
89) -> c_int {
90 unsafe {
91 ptr::copy_nonoverlapping(data as *const c_uchar, nonce32, 32);
92 }
93 1
94}
95
96fn create_schnorr_hash(msg: &Message, nonce: &XOnlyPublicKey, pubkey: &XOnlyPublicKey) -> [u8; 32] {
97 let mut buf = Vec::<u8>::new();
98 buf.extend(nonce.serialize());
99 buf.extend(pubkey.serialize());
100 buf.extend(msg.as_ref().to_vec());
101 BIP340Hash::hash(&buf).to_byte_array()
102}
103
104fn schnorr_pubkey_to_pubkey(schnorr_pubkey: &XOnlyPublicKey) -> Result<PublicKey, Error> {
105 let mut buf = Vec::<u8>::with_capacity(33);
106 buf.push(0x02);
107 buf.extend(schnorr_pubkey.serialize());
108 Ok(PublicKey::from_slice(&buf)?)
109}