1
2use std::fmt;
3
4pub use secp256k1_musig as secpm;
5pub use secp256k1_musig::musig::{
6 AggregatedNonce, PublicNonce, PartialSignature, SecretNonce, Session, SessionSecretRand,
7};
8
9
10use bitcoin::secp256k1::{schnorr, Keypair, PublicKey, SecretKey};
11use secpm::ffi::MUSIG_SECNONCE_SIZE;
12use secpm::musig::KeyAggCache;
13
14lazy_static! {
15 pub static ref SECP: secpm::Secp256k1<secpm::All> = secpm::Secp256k1::new();
17}
18
19pub fn pubkey_to(pk: PublicKey) -> secpm::PublicKey {
20 secpm::PublicKey::from_slice(&pk.serialize_uncompressed()).unwrap()
21}
22
23pub fn pubkey_from(pk: secpm::PublicKey) -> PublicKey {
24 PublicKey::from_slice(&pk.serialize_uncompressed()).unwrap()
25}
26
27pub fn seckey_to(sk: SecretKey) -> secpm::SecretKey {
28 secpm::SecretKey::from_secret_bytes(sk.secret_bytes()).unwrap()
29}
30
31pub fn keypair_to(kp: &Keypair) -> secpm::Keypair {
32 secpm::Keypair::from_seckey_byte_array(kp.secret_bytes()).unwrap()
33}
34
35pub fn keypair_from(kp: &secpm::Keypair) -> Keypair {
36 Keypair::from_seckey_slice(&crate::SECP, &kp.to_secret_bytes()).unwrap()
37}
38
39pub fn sig_from(s: secpm::schnorr::Signature) -> schnorr::Signature {
40 schnorr::Signature::from_slice(&s.to_byte_array()).unwrap()
41}
42
43pub fn key_agg<'a>(keys: impl IntoIterator<Item = PublicKey>) -> KeyAggCache {
47 let mut keys = keys.into_iter().map(|k| pubkey_to(k)).collect::<Vec<_>>();
48 keys.sort_by_key(|k| k.serialize());
49 let keys = keys.iter().collect::<Vec<_>>(); KeyAggCache::new(&keys)
51}
52
53pub fn tweaked_key_agg<'a>(
58 keys: impl IntoIterator<Item = PublicKey>,
59 tweak: [u8; 32],
60) -> (KeyAggCache, PublicKey) {
61 let mut keys = keys.into_iter().map(|k| pubkey_to(k)).collect::<Vec<_>>();
62 keys.sort_by_key(|k| k.serialize());
63 let keys = keys.iter().collect::<Vec<_>>(); let mut ret = KeyAggCache::new(&keys);
65 let tweak_scalar = secpm::Scalar::from_be_bytes(tweak).unwrap();
66 let pk = ret.pubkey_xonly_tweak_add(&tweak_scalar).unwrap();
67 (ret, pubkey_from(pk))
68}
69
70pub fn combine_keys(keys: impl IntoIterator<Item = PublicKey>) -> PublicKey {
74 pubkey_from(key_agg(keys).agg_pk_full())
75}
76
77pub fn nonce_pair(key: &Keypair) -> (SecretNonce, PublicNonce) {
78 let kp = keypair_to(key);
79 secpm::musig::new_nonce_pair(
80 SessionSecretRand::assume_unique_per_nonce_gen(rand::random()),
81 None,
82 Some(kp.secret_key()),
83 kp.public_key(),
84 None,
85 Some(rand::random()),
86 )
87}
88
89pub fn nonce_pair_with_msg(key: &Keypair, msg: &[u8; 32]) -> (SecretNonce, PublicNonce) {
90 let kp = keypair_to(key);
91 secpm::musig::new_nonce_pair(
92 SessionSecretRand::assume_unique_per_nonce_gen(rand::random()),
93 None,
94 Some(kp.secret_key()),
95 kp.public_key(),
96 Some(msg),
97 Some(rand::random()),
98 )
99}
100
101pub fn nonce_agg(pub_nonces: &[&PublicNonce]) -> AggregatedNonce {
102 AggregatedNonce::new(pub_nonces)
103}
104
105pub fn combine_partial_signatures(
106 pubkeys: impl IntoIterator<Item = PublicKey>,
107 agg_nonce: AggregatedNonce,
108 sighash: [u8; 32],
109 tweak: Option<[u8; 32]>,
110 sigs: &[&PartialSignature],
111) -> schnorr::Signature {
112 let agg = if let Some(tweak) = tweak {
113 tweaked_key_agg(pubkeys, tweak).0
114 } else {
115 key_agg(pubkeys)
116 };
117
118 let session = Session::new(&agg, agg_nonce, &sighash);
119 sig_from(session.partial_sig_agg(&sigs).assume_valid())
120}
121
122pub fn partial_sign(
123 pubkeys: impl IntoIterator<Item = PublicKey>,
124 agg_nonce: AggregatedNonce,
125 key: &Keypair,
126 sec_nonce: SecretNonce,
127 sighash: [u8; 32],
128 tweak: Option<[u8; 32]>,
129 other_sigs: Option<&[&PartialSignature]>,
130) -> (PartialSignature, Option<schnorr::Signature>) {
131 let agg = if let Some(tweak) = tweak {
132 tweaked_key_agg(pubkeys, tweak).0
133 } else {
134 key_agg(pubkeys)
135 };
136
137 let session = Session::new(&agg, agg_nonce, &sighash);
138 let my_sig = session.partial_sign(sec_nonce, &keypair_to(&key), &agg);
139 let final_sig = if let Some(others) = other_sigs {
140 let mut sigs = Vec::with_capacity(others.len() + 1);
141 sigs.extend_from_slice(others);
142 sigs.push(&my_sig);
143 Some(session.partial_sig_agg(&sigs))
144 } else {
145 None
146 };
147 (my_sig, final_sig.map(|s| sig_from(s.assume_valid())))
148}
149
150pub fn deterministic_partial_sign(
156 my_key: &Keypair,
157 their_pubkeys: impl IntoIterator<Item = PublicKey>,
158 their_nonces: &[&PublicNonce],
159 msg: [u8; 32],
160 tweak: Option<[u8; 32]>,
161) -> (PublicNonce, PartialSignature) {
162 let agg = if let Some(tweak) = tweak {
163 tweaked_key_agg(their_pubkeys.into_iter().chain(Some(my_key.public_key())), tweak).0
164 } else {
165 key_agg(their_pubkeys.into_iter().chain(Some(my_key.public_key())))
166 };
167
168 let (sec_nonce, pub_nonce) = secpm::musig::new_nonce_pair(
169 SessionSecretRand::assume_unique_per_nonce_gen(rand::random()),
170 Some(&agg),
171 Some(seckey_to(my_key.secret_key())),
172 pubkey_to(my_key.public_key()),
173 Some(&msg),
174 Some(rand::random()),
175 );
176
177 let nonces = their_nonces.into_iter().map(|n| *n).chain(Some(&pub_nonce)).collect::<Vec<_>>();
178 let agg_nonce = AggregatedNonce::new(&nonces);
179 let session = Session::new(&agg, agg_nonce, &msg);
180 let sig = session.partial_sign(sec_nonce, &keypair_to(my_key), &agg);
181 (pub_nonce, sig)
182}
183
184pub fn cosign_both(
192 user_keypair: &Keypair,
193 server_keypair: &Keypair,
194 msg: [u8; 32],
195 tweak: Option<[u8; 32]>,
196) -> schnorr::Signature {
197 let (user_sec_nonce, user_pub_nonce) = nonce_pair(user_keypair);
198
199 let (server_pub_nonce, server_partial_sig) = deterministic_partial_sign(
200 server_keypair,
201 [user_keypair.public_key()],
202 &[&user_pub_nonce],
203 msg,
204 tweak,
205 );
206
207 let agg_nonce = nonce_agg(&[&user_pub_nonce, &server_pub_nonce]);
208 let (_partial, full_sig) = partial_sign(
209 [user_keypair.public_key(), server_keypair.public_key()],
210 agg_nonce,
211 user_keypair,
212 user_sec_nonce,
213 msg,
214 tweak,
215 Some(&[&server_partial_sig]),
216 );
217
218 full_sig.expect("full sig must exist when server partial is provided")
219}
220
221pub mod serde {
223 use super::*;
224 use ::serde::{Deserializer, Serializer};
225 use ::serde::de::{self, Error};
226
227 pub(super) struct BytesVisitor;
228 impl<'de> de::Visitor<'de> for BytesVisitor {
229 type Value = Vec<u8>;
230 fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 write!(f, "a byte object")
232 }
233 fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
234 Ok(v.to_vec())
235 }
236 fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
237 Ok(v)
238 }
239 }
240
241 pub mod pubnonce {
242 use super::*;
243 pub fn serialize<S: Serializer>(pub_nonce: &PublicNonce, s: S) -> Result<S::Ok, S::Error> {
244 s.serialize_bytes(&pub_nonce.serialize())
245 }
246 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<PublicNonce, D::Error> {
247 let v = d.deserialize_byte_buf(BytesVisitor)?;
248 let b = TryFrom::try_from(&v[..]).map_err(D::Error::custom)?;
249 PublicNonce::from_byte_array(b).map_err(D::Error::custom)
250 }
251 }
252 pub mod partialsig {
253 use super::*;
254 pub fn serialize<S: Serializer>(sig: &PartialSignature, s: S) -> Result<S::Ok, S::Error> {
255 s.serialize_bytes(&sig.serialize())
256 }
257 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<PartialSignature, D::Error> {
258 let v = d.deserialize_byte_buf(BytesVisitor)?;
259 let b = TryFrom::try_from(&v[..]).map_err(D::Error::custom)?;
260 PartialSignature::from_byte_array(b).map_err(D::Error::custom)
261 }
262 }
263}
264#[derive(Clone, PartialEq, Eq)]
267pub struct DangerousSecretNonce([u8; MUSIG_SECNONCE_SIZE]);
268
269impl DangerousSecretNonce {
270 pub fn dangerous_from_secret_nonce(n: SecretNonce) -> Self {
271 DangerousSecretNonce(n.dangerous_into_bytes())
272 }
273
274 pub fn to_sec_nonce(&self) -> SecretNonce {
275 SecretNonce::dangerous_from_bytes(self.0.clone())
276 }
277
278 pub fn serialize(&self) -> [u8; MUSIG_SECNONCE_SIZE] {
279 self.0.clone()
280 }
281
282 pub fn from_byte_array(bytes: [u8; MUSIG_SECNONCE_SIZE]) -> Self {
283 Self(bytes)
284 }
285}
286
287impl fmt::Debug for DangerousSecretNonce {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 f.write_str("[secret nonces redacted]")
290 }
291}
292
293impl ::serde::Serialize for DangerousSecretNonce {
294 fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
295 s.serialize_bytes(&self.0[..])
296 }
297}
298
299impl<'de> ::serde::Deserialize<'de> for DangerousSecretNonce {
300 fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
301
302 struct Visitor;
305 impl<'de> ::serde::de::Visitor<'de> for Visitor {
306 type Value = DangerousSecretNonce;
307 fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
308 write!(f, "a sercret musig nonce")
309 }
310 fn visit_bytes<E: ::serde::de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
311 TryFrom::try_from(v)
312 .map(DangerousSecretNonce::from_byte_array)
313 .map_err(|_| ::serde::de::Error::custom("invalid nonce"))
314 }
315 fn visit_seq<A: ::serde::de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
317 let mut buf = Vec::with_capacity(MUSIG_SECNONCE_SIZE);
318 while let Some(e) = seq.next_element::<u8>()? {
319 buf.push(e);
320 }
321
322 TryFrom::try_from(&buf[..])
323 .map(DangerousSecretNonce::from_byte_array)
324 .map_err(|_| ::serde::de::Error::custom("invalid nonce"))
325 }
326 }
327
328 d.deserialize_any(Visitor)
329 }
330}
331
332#[cfg(test)]
333mod test {
334 use super::*;
335
336 #[test]
337 fn check_secnonce_serde_backwards_compat() {
338 let old_example = "[34,14,220,241,180,58,27,107,242,94,46,188,49,93,184,43,106,56,122,169,152,94,66,191,174,151,204,92,46,98,136,90,36,157,87,31,121,220,132,111,215,45,84,171,202,93,147,0,95,177,81,31,9,178,49,66,6,46,48,146,122,120,169,193,196,26,248,12,254,130,145,44,72,98,212,216,130,188,160,32,233,255,151,175,212,179,236,166,29,124,170,6,105,95,89,39,57,90,229,234,160,79,115,5,71,11,180,46,211,198,109,140,248,12,53,4,246,201,129,87,194,97,237,214,255,196,105,121,180,98,60,132]";
339 let _ = serde_json::from_str::<DangerousSecretNonce>(old_example).unwrap();
340 }
341}