Skip to content

Commit 99d1b1a

Browse files
committed
More doc and usability improvements
1 parent 4c79aa5 commit 99d1b1a

File tree

1 file changed

+67
-13
lines changed

1 file changed

+67
-13
lines changed

schnorr_fun/src/musig.rs

+67-13
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
//! // Since we're using deterministic nonces it's important we only use the session id once
3232
//! let my_nonces = musig.gen_nonces(&keylist, b"session-id-1337");
3333
//! // send this to the other parties
34-
//! let my_public_nonce = my_nonces[0].public;
34+
//! let my_public_nonce = my_nonces[0].public();
3535
//! # let nonces = musig.gen_nonces(&_keylist, b"session-id-1337");
36-
//! # let p1_nonce = nonces[0].public;
37-
//! # let p3_nonce = nonces[1].public;
38-
//! # let mut _session = musig.start_sign_session_deterministic(&_keylist, my_nonces.iter().map(|n| n.public), b"session-id-1337", message).unwrap();
36+
//! # let p1_nonce = nonces[0].public();
37+
//! # let p3_nonce = nonces[1].public();
38+
//! # let mut _session = musig.start_sign_session_deterministic(&_keylist, my_nonces.iter().map(|n| n.public()), b"session-id-1337", message).unwrap();
3939
//! // Once you've got the nonces from the other two (p1_nonce and p3_nonce) you can start the signing session.
4040
//! let mut session = musig.start_sign_session(&keylist, my_nonces, [p1_nonce, p3_nonce], message).unwrap();
4141
//! // but since we're using deterministic nonce generation we can just remember the session id.
@@ -58,7 +58,7 @@
5858
//! ## Description
5959
//!
6060
//! The MuSig2 multisignature scheme lets you aggregate multiple public keys into a single public
61-
//! key that requires each corresponding secret key to authorize signatures under the aggregate key.
61+
//! key that requires all of the corresponding secret keys to authorize a signature under the aggregate key.
6262
//!
6363
//! This implementation is protocol compatible with the implementation merged into
6464
//! [secp256k1-zkp].
@@ -145,9 +145,13 @@ pub enum Party {
145145
Remote(XOnly),
146146
}
147147

148-
/// A struct which represents a list of keys aggregated into a single key.
148+
/// A list of keys aggregated into a single key.
149149
///
150-
/// This can't be serialized but it's very efficient to re-create it from the initial list of keys.
150+
/// Created using [`MuSig::new_keylist`].
151+
///
152+
/// The `KeyList` can't be serialized but it's very efficient to re-create it from the initial list of keys.
153+
///
154+
/// [`MuSig::new_keylist`]
151155
#[derive(Debug, Clone)]
152156
pub struct KeyList {
153157
/// The parties involved in the key aggregation.
@@ -203,7 +207,7 @@ impl KeyList {
203207
///
204208
/// Returns a new keylist with the same parties but a different aggregated public key. In the
205209
/// unusual case that the tweak is exactly equal to the negation of the aggregated secret key
206-
/// this returns `None`.
210+
/// it returns `None`.
207211
pub fn tweak(&self, tweak: Scalar<impl Secrecy, impl ZeroChoice>) -> Option<Self> {
208212
let mut tweak = s!(self.tweak + tweak).mark::<Public>();
209213
let (agg_key, needs_negation) = g!(self.agg_key + tweak * G)
@@ -331,16 +335,42 @@ secp256kfun::impl_display_serialize! {
331335

332336
/// A pair of secret nonces along with the public portion.
333337
///
334-
/// Depending on whether you are using deterministic nonce derivation or not
338+
/// A nonce key pair can be created manually with [`from_secrets`] or with [`MuSig::gen_nonces`].
339+
///
340+
/// [`from_secrets`]: Self::from_secrets
341+
/// [`MuSig::gen_nonces`]: Self::gen_nonces
335342
#[derive(Debug, Clone, PartialEq)]
336343
pub struct NonceKeyPair {
337344
/// The public nonce
338-
pub public: Nonce,
345+
public: Nonce,
339346
/// The secret nonce
340-
pub secret: [Scalar; 2],
347+
secret: [Scalar; 2],
341348
}
342349

343350
impl NonceKeyPair {
351+
/// Creates a keypair from two secret scalars.
352+
///
353+
/// ## Security
354+
///
355+
/// You must never use the same `NonceKeyPair` into two signing sessions.
356+
///
357+
/// ## Example
358+
/// ```
359+
/// use schnorr_fun::{ fun::Scalar, musig::NonceKeyPair };
360+
/// let nkp = NonceKeyPair::from_secrets([
361+
/// Scalar::random(&mut rand::thread_rng()),
362+
/// Scalar::random(&mut rand::thread_rng())
363+
/// ]);
364+
/// ```
365+
pub fn from_secrets(secret: [Scalar;2]) -> Self {
366+
let [ref r1, ref r2] = secret;
367+
let R1 = g!(r1 * G).normalize();
368+
let R2 = g!(r2 * G).normalize();
369+
NonceKeyPair {
370+
public: Nonce([R1,R2]),
371+
secret
372+
}
373+
}
344374
/// Deserializes a nonce key pair from 64-bytes (two 32-byte serialized scalars).
345375
pub fn from_bytes(bytes: [u8; 64]) -> Option<Self> {
346376
let r1 = Scalar::from_slice(&bytes[..32])?.mark::<NonZero>()?;
@@ -361,6 +391,16 @@ impl NonceKeyPair {
361391
bytes[32..].copy_from_slice(self.secret[1].to_bytes().as_ref());
362392
bytes
363393
}
394+
395+
/// Get the secret portion of the nonce key pair (don't share this!)
396+
pub fn secret(&self) -> &[Scalar;2] {
397+
&self.secret
398+
}
399+
400+
/// Get the public portion of the nonce key pair (share this!)
401+
pub fn public(&self) -> Nonce {
402+
self.public
403+
}
364404
}
365405

366406
secp256kfun::impl_fromstr_deserialize! {
@@ -497,7 +537,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> MuSig<H, Schnorr<H, NG>> {
497537
/// Start a signing session.
498538
///
499539
/// You must provide you local secret nonces (the public portion must be shared with the other signer(s)).
500-
/// If you are using deterministic signing it's possible to use [`start_sign_session_deterministic`] instead.
540+
/// If you are using deterministic nonce generations it's possible to use [`start_sign_session_deterministic`] instead.
501541
///
502542
/// ## Return Value
503543
///
@@ -538,9 +578,10 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> MuSig<H, Schnorr<H, NG>> {
538578
/// Start an encrypted signing session.
539579
///
540580
/// i.e. a session to produce an adaptor signature under `encryption_key`.
581+
/// See [`adaptor`] for a more general description of adaptor signatures.
541582
///
542583
/// You must provide you local secret nonces (the public portion must be shared with the other
543-
/// signer(s)). If you are using deterministic signing it's possible to use
584+
/// signer(s)). If you are using deterministic nonce generation it's possible to use
544585
/// [`start_encrypted_sign_session_deterministic`] instead.
545586
///
546587
/// ## Return Value
@@ -555,6 +596,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> MuSig<H, Schnorr<H, NG>> {
555596
/// `keylist`.
556597
///
557598
/// [`start_encrypted_sign_session_deterministic`]: Self::start_sign_session_deterministic
599+
/// [`adaptor`]: crate::adaptor
558600
pub fn start_encrypted_sign_session(
559601
&self,
560602
keylist: &KeyList,
@@ -789,6 +831,12 @@ where
789831
/// Same as [`start_sign_session`] but re-generate the local nonces deterministically from the
790832
/// `sid` instead of passing them in.
791833
///
834+
/// ## Security
835+
///
836+
/// Each call to this function must have a unique `sid`. Never call it twice with the same
837+
/// `sid`, otherwise you risk revealing your secret key with the two signatures generated from
838+
/// it if `message` or `remote_nonces` changes.
839+
///
792840
/// [`start_sign_session`]: Self::start_sign_session
793841
pub fn start_sign_session_deterministic(
794842
&self,
@@ -804,6 +852,12 @@ where
804852
/// Same as [`start_encrypted_sign_session`] but re-generate the local nonces deterministically from the
805853
/// `sid` instead of passing them in.
806854
///
855+
/// ## Security
856+
///
857+
/// Each call to this function must have a unique `sid`. Never call it twice with the same
858+
/// `sid`, otherwise you risk revealing your secret key with the two signatures generated from
859+
/// it if `message` or `remote_nonces` changes.
860+
///
807861
/// [`start_encrypted_sign_session`]: Self::start_encrypted_sign_session
808862
pub fn start_encrypted_sign_session_deterministic(
809863
&self,

0 commit comments

Comments
 (0)