ark/
musig.rs

1
2use secp256k1_musig::ffi::MUSIG_SECNONCE_SIZE;
3pub use secp256k1_musig as secpm;
4pub use secp256k1_musig::musig::{
5	AggregatedNonce, PublicNonce, PartialSignature, SecretNonce, Session, SessionSecretRand,
6};
7
8use bitcoin::secp256k1::{rand, schnorr, Keypair, PublicKey, SecretKey, XOnlyPublicKey};
9use secpm::musig::KeyAggCache;
10
11lazy_static! {
12	/// Global secp context.
13	pub static ref SECP: secpm::Secp256k1<secpm::All> = secpm::Secp256k1::new();
14}
15
16pub fn xonly_from(pk: secpm::XOnlyPublicKey) -> XOnlyPublicKey {
17	XOnlyPublicKey::from_slice(&pk.serialize()).unwrap()
18}
19
20pub fn pubkey_to(pk: PublicKey) -> secpm::PublicKey {
21	secpm::PublicKey::from_slice(&pk.serialize_uncompressed()).unwrap()
22}
23
24pub fn pubkey_from(pk: secpm::PublicKey) -> PublicKey {
25	PublicKey::from_slice(&pk.serialize_uncompressed()).unwrap()
26}
27
28pub fn seckey_to(sk: SecretKey) -> secpm::SecretKey {
29	secpm::SecretKey::from_secret_bytes(sk.secret_bytes()).unwrap()
30}
31
32pub fn keypair_to(kp: &Keypair) -> secpm::Keypair {
33	secpm::Keypair::from_seckey_byte_array(kp.secret_bytes()).unwrap()
34}
35
36pub fn keypair_from(kp: &secpm::Keypair) -> Keypair {
37	Keypair::from_seckey_slice(&crate::SECP, &kp.secret_bytes()).unwrap()
38}
39
40pub fn sig_from(s: secpm::schnorr::Signature) -> schnorr::Signature {
41	schnorr::Signature::from_slice(&s.to_byte_array()).unwrap()
42}
43
44/// Returns the key agg cache and the resulting pubkey.
45///
46/// Key order is not important as keys are sorted before aggregation.
47pub fn key_agg<'a>(keys: impl IntoIterator<Item = PublicKey>) -> KeyAggCache {
48	let mut keys = keys.into_iter().map(|k| pubkey_to(k)).collect::<Vec<_>>();
49	keys.sort_by_key(|k| k.serialize());
50	let keys = keys.iter().collect::<Vec<_>>(); //TODO(stevenroose) remove when musig pr merged
51	KeyAggCache::new(&keys)
52}
53
54/// Returns the key agg cache with the tweak applied and the resulting pubkey
55/// with the tweak applied.
56///
57/// Key order is not important as keys are sorted before aggregation.
58pub fn tweaked_key_agg<'a>(
59	keys: impl IntoIterator<Item = PublicKey>,
60	tweak: [u8; 32],
61) -> (KeyAggCache, PublicKey) {
62	let mut keys = keys.into_iter().map(|k| pubkey_to(k)).collect::<Vec<_>>();
63	keys.sort_by_key(|k| k.serialize());
64	let keys = keys.iter().collect::<Vec<_>>(); //TODO(stevenroose) remove when musig pr merged
65	let mut ret = KeyAggCache::new(&keys);
66	let tweak_scalar = secpm::Scalar::from_be_bytes(tweak).unwrap();
67	let pk = ret.pubkey_xonly_tweak_add(&tweak_scalar).unwrap();
68	(ret, pubkey_from(pk))
69}
70
71/// Aggregates the public keys into their aggregate public key.
72///
73/// Key order is not important as keys are sorted before aggregation.
74pub fn combine_keys(keys: impl IntoIterator<Item = PublicKey>) -> XOnlyPublicKey {
75	xonly_from(key_agg(keys).agg_pk())
76}
77
78pub fn nonce_pair(key: &Keypair) -> (SecretNonce, PublicNonce) {
79	let kp = keypair_to(key);
80	secpm::musig::new_nonce_pair(
81		SessionSecretRand::assume_unique_per_nonce_gen(rand::random()),
82		None,
83		Some(kp.secret_key()),
84		kp.public_key(),
85		None,
86		Some(rand::random()),
87	)
88}
89
90pub fn nonce_pair_with_msg(key: &Keypair, msg: &[u8; 32]) -> (SecretNonce, PublicNonce) {
91	let kp = keypair_to(key);
92	secpm::musig::new_nonce_pair(
93		SessionSecretRand::assume_unique_per_nonce_gen(rand::random()),
94		None,
95		Some(kp.secret_key()),
96		kp.public_key(),
97		Some(msg),
98		Some(rand::random()),
99	)
100}
101
102pub fn nonce_agg(pub_nonces: &[&PublicNonce]) -> AggregatedNonce {
103	AggregatedNonce::new(pub_nonces)
104}
105
106pub fn combine_partial_signatures(
107	pubkeys: impl IntoIterator<Item = PublicKey>,
108	agg_nonce: AggregatedNonce,
109	sighash: [u8; 32],
110	tweak: Option<[u8; 32]>,
111	sigs: &[&PartialSignature],
112) -> schnorr::Signature {
113	let agg = if let Some(tweak) = tweak {
114		tweaked_key_agg(pubkeys, tweak).0
115	} else {
116		key_agg(pubkeys)
117	};
118
119	let session = Session::new(&agg, agg_nonce, &sighash);
120	sig_from(session.partial_sig_agg(&sigs).assume_valid())
121}
122
123pub fn partial_sign(
124	pubkeys: impl IntoIterator<Item = PublicKey>,
125	agg_nonce: AggregatedNonce,
126	key: &Keypair,
127	sec_nonce: SecretNonce,
128	sighash: [u8; 32],
129	tweak: Option<[u8; 32]>,
130	other_sigs: Option<&[&PartialSignature]>,
131) -> (PartialSignature, Option<schnorr::Signature>) {
132	let agg = if let Some(tweak) = tweak {
133		tweaked_key_agg(pubkeys, tweak).0
134	} else {
135		key_agg(pubkeys)
136	};
137
138	let session = Session::new(&agg, agg_nonce, &sighash);
139	let my_sig = session.partial_sign(sec_nonce, &keypair_to(&key), &agg);
140	let final_sig = if let Some(others) = other_sigs {
141		let mut sigs = Vec::with_capacity(others.len() + 1);
142		sigs.extend_from_slice(others);
143		sigs.push(&my_sig);
144		Some(session.partial_sig_agg(&sigs))
145	} else {
146		None
147	};
148	(my_sig, final_sig.map(|s| sig_from(s.assume_valid())))
149}
150
151/// Perform a deterministic partial sign for the given message and the
152/// given counterparty key and nonce.
153///
154/// This is only possible for the first party to sign if it has all the
155/// counterparty nonces.
156pub fn deterministic_partial_sign(
157	my_key: &Keypair,
158	their_pubkeys: impl IntoIterator<Item = PublicKey>,
159	their_nonces: &[&PublicNonce],
160	msg: [u8; 32],
161	tweak: Option<[u8; 32]>,
162) -> (PublicNonce, PartialSignature) {
163	let agg = if let Some(tweak) = tweak {
164		tweaked_key_agg(their_pubkeys.into_iter().chain(Some(my_key.public_key())), tweak).0
165	} else {
166		key_agg(their_pubkeys.into_iter().chain(Some(my_key.public_key())))
167	};
168
169	let (sec_nonce, pub_nonce) = secpm::musig::new_nonce_pair(
170		SessionSecretRand::assume_unique_per_nonce_gen(rand::random()),
171		Some(&agg),
172		Some(seckey_to(my_key.secret_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//TODO(stevenroose) probably get rid of all this by having native byte serializers in secp
186pub mod serde {
187	use super::*;
188	use ::serde::{Deserializer, Serializer};
189	use ::serde::de::{self, Error};
190
191	struct BytesVisitor;
192	impl<'de> de::Visitor<'de> for BytesVisitor {
193		type Value = Vec<u8>;
194		fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195			write!(f, "a byte object")
196		}
197		fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
198			Ok(v.to_vec())
199		}
200		fn visit_borrowed_bytes<E: de::Error>(self, v: &'de [u8]) -> Result<Self::Value, E> {
201			Ok(v.to_vec())
202		}
203		fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
204			Ok(v)
205		}
206	}
207
208	pub mod pubnonce {
209		use super::*;
210		pub fn serialize<S: Serializer>(pub_nonce: &PublicNonce, s: S) -> Result<S::Ok, S::Error> {
211			s.serialize_bytes(&pub_nonce.serialize())
212		}
213		pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<PublicNonce, D::Error> {
214			let v = d.deserialize_byte_buf(BytesVisitor)?;
215			let b = TryFrom::try_from(&v[..]).map_err(D::Error::custom)?;
216			PublicNonce::from_byte_array(b).map_err(D::Error::custom)
217		}
218	}
219	pub mod partialsig {
220		use super::*;
221		pub fn serialize<S: Serializer>(sig: &PartialSignature, s: S) -> Result<S::Ok, S::Error> {
222			s.serialize_bytes(&sig.serialize())
223		}
224		pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<PartialSignature, D::Error> {
225			let v = d.deserialize_byte_buf(BytesVisitor)?;
226			let b = TryFrom::try_from(&v[..]).map_err(D::Error::custom)?;
227			PartialSignature::from_byte_array(b).map_err(D::Error::custom)
228		}
229	}
230}
231/// A type that actually represents a [SecretNonce] but without the
232/// typesystem defenses for dangerous usage.
233#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
234pub struct DangerousSecretNonce(Vec<u8>);
235
236impl DangerousSecretNonce {
237	pub fn new(n: SecretNonce) -> Self {
238		DangerousSecretNonce(n.dangerous_into_bytes().to_vec())
239	}
240
241	pub fn to_sec_nonce(&self) -> SecretNonce {
242		assert_eq!(self.0.len(), MUSIG_SECNONCE_SIZE);
243		SecretNonce::dangerous_from_bytes(TryFrom::try_from(&self.0[..]).expect("right size"))
244	}
245}