Skip to main content

ark/
musig.rs

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	/// Global secp context.
16	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_secret_bytes(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
43/// Returns the key agg cache and the resulting pubkey.
44///
45/// Key order is not important as keys are sorted before aggregation.
46pub 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<_>>(); //TODO(stevenroose) remove when musig pr merged
50	KeyAggCache::new(&keys)
51}
52
53/// Returns the key agg cache with the tweak applied and the resulting pubkey
54/// with the tweak applied.
55///
56/// Key order is not important as keys are sorted before aggregation.
57pub 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<_>>(); //TODO(stevenroose) remove when musig pr merged
64	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
70/// Aggregates the public keys into their aggregate public key.
71///
72/// Key order is not important as keys are sorted before aggregation.
73pub 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(), &kp.secret_key()),
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(), &kp.secret_key()),
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().saturating_add(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
150/// Perform a deterministic partial sign for the given message and the
151/// given counterparty key and nonce.
152///
153/// This is only possible for the first party to sign if it has all the
154/// counterparty nonces.
155pub 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 my_sec_key = seckey_to(my_key.secret_key());
169	let (sec_nonce, pub_nonce) = secpm::musig::new_nonce_pair(
170		SessionSecretRand::assume_unique_per_nonce_gen(rand::random(), &my_sec_key),
171		Some(&agg),
172		Some(my_sec_key),
173		pubkey_to(my_key.public_key()),
174		Some(&msg),
175		Some(rand::random()),
176	);
177
178	let nonces = their_nonces.into_iter().map(|n| *n).chain(Some(&pub_nonce)).collect::<Vec<_>>();
179	let agg_nonce = AggregatedNonce::new(&nonces);
180	let session = Session::new(&agg, agg_nonce, &msg);
181	let sig = session.partial_sign(sec_nonce, &keypair_to(my_key), &agg);
182	(pub_nonce, sig)
183}
184
185/// Sign a 2-of-2 musig when you hold both keypairs.
186///
187/// This is stupid: there is no point in doing musig if you have access
188/// to both keys. We need it because the vtxopool owns VTXOs that are
189/// locked under a user+server musig key, and we need to spend them
190/// without changing the key structure. So we do the full musig2 dance
191/// with ourselves.
192pub fn cosign_both(
193	user_keypair: &Keypair,
194	server_keypair: &Keypair,
195	msg: [u8; 32],
196	tweak: Option<[u8; 32]>,
197) -> schnorr::Signature {
198	let (user_sec_nonce, user_pub_nonce) = nonce_pair(user_keypair);
199
200	let (server_pub_nonce, server_partial_sig) = deterministic_partial_sign(
201		server_keypair,
202		[user_keypair.public_key()],
203		&[&user_pub_nonce],
204		msg,
205		tweak,
206	);
207
208	let agg_nonce = nonce_agg(&[&user_pub_nonce, &server_pub_nonce]);
209	let (_partial, full_sig) = partial_sign(
210		[user_keypair.public_key(), server_keypair.public_key()],
211		agg_nonce,
212		user_keypair,
213		user_sec_nonce,
214		msg,
215		tweak,
216		Some(&[&server_partial_sig]),
217	);
218
219	full_sig.expect("full sig must exist when server partial is provided")
220}
221
222//TODO(stevenroose) probably get rid of all this by having native byte serializers in secp
223pub mod serde {
224	use super::*;
225	use ::serde::{Deserializer, Serializer};
226	use ::serde::de::{self, Error};
227
228	pub(super) struct BytesVisitor;
229	impl<'de> de::Visitor<'de> for BytesVisitor {
230		type Value = Vec<u8>;
231		fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232			write!(f, "a byte object")
233		}
234		fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
235			Ok(v.to_vec())
236		}
237		fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
238			Ok(v)
239		}
240	}
241
242	pub mod pubnonce {
243		use super::*;
244		pub fn serialize<S: Serializer>(pub_nonce: &PublicNonce, s: S) -> Result<S::Ok, S::Error> {
245			s.serialize_bytes(&pub_nonce.serialize())
246		}
247		pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<PublicNonce, D::Error> {
248			let v = d.deserialize_byte_buf(BytesVisitor)?;
249			let b = TryFrom::try_from(&v[..]).map_err(D::Error::custom)?;
250			PublicNonce::from_byte_array(b).map_err(D::Error::custom)
251		}
252	}
253	pub mod partialsig {
254		use super::*;
255		pub fn serialize<S: Serializer>(sig: &PartialSignature, s: S) -> Result<S::Ok, S::Error> {
256			s.serialize_bytes(&sig.serialize())
257		}
258		pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<PartialSignature, D::Error> {
259			let v = d.deserialize_byte_buf(BytesVisitor)?;
260			let b = TryFrom::try_from(&v[..]).map_err(D::Error::custom)?;
261			PartialSignature::from_byte_array(b).map_err(D::Error::custom)
262		}
263	}
264}
265/// A type that actually represents a [SecretNonce] but without the
266/// typesystem defenses for dangerous usage.
267#[derive(Clone, PartialEq, Eq)]
268pub struct DangerousSecretNonce([u8; MUSIG_SECNONCE_SIZE]);
269
270impl DangerousSecretNonce {
271	pub fn dangerous_from_secret_nonce(n: SecretNonce) -> Self {
272		DangerousSecretNonce(n.dangerous_into_bytes())
273	}
274
275	pub fn to_sec_nonce(&self) -> SecretNonce {
276		SecretNonce::dangerous_from_bytes(self.0.clone())
277	}
278
279	pub fn serialize(&self) -> [u8; MUSIG_SECNONCE_SIZE] {
280		self.0.clone()
281	}
282
283	pub fn from_byte_array(bytes: [u8; MUSIG_SECNONCE_SIZE]) -> Self {
284		Self(bytes)
285	}
286}
287
288impl fmt::Debug for DangerousSecretNonce {
289	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290	    f.write_str("[secret nonces redacted]")
291	}
292}
293
294impl ::serde::Serialize for DangerousSecretNonce {
295	fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
296		s.serialize_bytes(&self.0[..])
297	}
298}
299
300impl<'de> ::serde::Deserialize<'de> for DangerousSecretNonce {
301	fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
302
303		// can eventually use self::serde::BytesVisitor,
304		// but we now also accept lists to be backwards compatible with Vec<u8>
305		struct Visitor;
306		impl<'de> ::serde::de::Visitor<'de> for Visitor {
307			type Value = DangerousSecretNonce;
308			fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
309				write!(f, "a sercret musig nonce")
310			}
311			fn visit_bytes<E: ::serde::de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
312				TryFrom::try_from(v)
313					.map(DangerousSecretNonce::from_byte_array)
314					.map_err(|_| ::serde::de::Error::custom("invalid nonce"))
315			}
316			// be compatible with previous serialization
317			fn visit_seq<A: ::serde::de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
318			    let mut buf = Vec::with_capacity(MUSIG_SECNONCE_SIZE);
319				while let Some(e) = seq.next_element::<u8>()? {
320					buf.push(e);
321				}
322
323				TryFrom::try_from(&buf[..])
324					.map(DangerousSecretNonce::from_byte_array)
325					.map_err(|_| ::serde::de::Error::custom("invalid nonce"))
326			}
327		}
328
329		d.deserialize_any(Visitor)
330	}
331}
332
333#[cfg(test)]
334mod test {
335	use super::*;
336
337	#[test]
338	fn check_secnonce_serde_backwards_compat() {
339		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]";
340		let _ = serde_json::from_str::<DangerousSecretNonce>(old_example).unwrap();
341	}
342}