From fdae0fd55eb5673bd5df1298f4594137bbfc4f2b Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Wed, 11 Jun 2025 17:10:56 +0000 Subject: [PATCH 1/4] typo: leak -> lead --- src/musig.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/musig.rs b/src/musig.rs index 7fd28b84f..5bb87c537 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -604,7 +604,7 @@ impl SecretNonce { /// /// # Warning: /// - /// Storing and re-creating this structure may leak to nonce reuse, which will leak + /// Storing and re-creating this structure may lead to nonce reuse, which will leak /// your secret key in two signing sessions, even if neither session is completed. /// These functions should be avoided if possible and used with care. /// From d318169a7c2d0d2cb3c96d61ae04bfd044c19b23 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Wed, 11 Jun 2025 17:10:56 +0000 Subject: [PATCH 2/4] musig: rename `musig_sort_pubkeys` to just `sort_pubkeys` This function is useful for Musig but may be useful elsewhere. Rename it to be more general, and mention it in the Musig docs. --- examples/musig.rs | 2 +- src/key.rs | 6 ++++-- src/musig.rs | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/musig.rs b/examples/musig.rs index 0f432bf5f..374d8b0db 100644 --- a/examples/musig.rs +++ b/examples/musig.rs @@ -19,7 +19,7 @@ fn main() { let mut pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); let pubkeys_ref = pubkeys_ref.as_mut_slice(); - secp.musig_sort_pubkeys(pubkeys_ref); + secp.sort_pubkeys(pubkeys_ref); let mut musig_key_agg_cache = KeyAggCache::new(&secp, pubkeys_ref); diff --git a/src/key.rs b/src/key.rs index b2e6b6874..9cf29200b 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1620,6 +1620,8 @@ impl<'de> serde::Deserialize<'de> for XOnlyPublicKey { impl Secp256k1 { /// Sort public keys using lexicographic (of compressed serialization) order. /// + /// This is the canonical way to sort public keys for use with Musig2. + /// /// Example: /// /// ```rust @@ -1636,10 +1638,10 @@ impl Secp256k1 { /// # let mut pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); /// # let pubkeys_ref = pubkeys_ref.as_mut_slice(); /// # - /// # secp.musig_sort_pubkeys(pubkeys_ref); + /// # secp.sort_pubkeys(pubkeys_ref); /// # } /// ``` - pub fn musig_sort_pubkeys(&self, pubkeys: &mut [&PublicKey]) { + pub fn sort_pubkeys(&self, pubkeys: &mut [&PublicKey]) { let cx = self.ctx().as_ptr(); unsafe { let mut pubkeys_ref = core::slice::from_raw_parts( diff --git a/src/musig.rs b/src/musig.rs index 5bb87c537..a663b3c66 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -281,6 +281,7 @@ impl KeyAggCache { /// ensures the same resulting `agg_pk` for the same multiset of pubkeys. /// This is useful to do before aggregating pubkeys, such that the order of pubkeys /// does not affect the combined public key. + /// To do this, call [`Secp256k1::sort_pubkeys`]. /// /// # Returns /// From 98bfb48b001002490e8a96d845fa21b05a2312f2 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Wed, 11 Jun 2025 17:22:55 +0000 Subject: [PATCH 3/4] musig: make zero-check in SessionSecretRand::assume_unique constant time I haven't checked against the assembler code and this check is simple enough that I suspect that the compiler is going to undermine me, but the use of ptr::read_volatile *should* prevent that. Anyway make a best-effort attempt. --- src/musig.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/musig.rs b/src/musig.rs index a663b3c66..96380614e 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -65,7 +65,13 @@ impl SessionSecretRand { /// a random number generator, or if that is not available, the output of a /// stable monotonic counter. pub fn assume_unique_per_nonce_gen(inner: [u8; 32]) -> Self { - assert_ne!(inner, [0; 32], "session secrets may not be all zero"); + // See SecretKey::eq for this "constant-time" algorithm for comparison against zero. + let inner_or = inner.iter().fold(0, |accum, x| accum | *x); + assert!( + unsafe { core::ptr::read_volatile(&inner_or) != 0 }, + "session secrets may not be all zero", + ); + SessionSecretRand(inner) } From 480370c6f87a5ee45bbea16df803a256e8bd435e Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Wed, 11 Jun 2025 17:25:44 +0000 Subject: [PATCH 4/4] ci: disable broken WASM and cross tests --- .github/workflows/cross.yml | 2 +- .github/workflows/rust.yml | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/cross.yml b/.github/workflows/cross.yml index 2d421f7fe..cf56da346 100644 --- a/.github/workflows/cross.yml +++ b/.github/workflows/cross.yml @@ -17,7 +17,7 @@ jobs: # - i686-pc-windows-msvc # not supported by cross - i686-unknown-linux-gnu # - x86_64-apple-darwin # proprietary apple stuff - - x86_64-pc-windows-gnu + # - x86_64-pc-windows-gnu # seems to be broken 2025-06 # - x86_64-pc-windows-msvc # not supported by cross - x86_64-unknown-linux-gnu ############ Tier 2 with Host Tools diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b8746b806..1ce314a97 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -253,19 +253,19 @@ jobs: - name: "Run test on i686" run: cargo test --target i686-unknown-linux-gnu - WASM: - name: WASM - stable toolchain - runs-on: ubuntu-latest - strategy: - fail-fast: false - # Note we do not use the recent lock file for wasm testing. - steps: - - name: "Checkout repo" - uses: actions/checkout@v4 - - name: "Select toolchain" - uses: dtolnay/rust-toolchain@stable - - name: "Run wasm script" - run: ./contrib/wasm.sh +# WASM: +# name: WASM - stable toolchain +# runs-on: ubuntu-latest +# strategy: +# fail-fast: false +# # Note we do not use the recent lock file for wasm testing. +# steps: +# - name: "Checkout repo" +# uses: actions/checkout@v4 +# - name: "Select toolchain" +# uses: dtolnay/rust-toolchain@stable +# - name: "Run wasm script" +# run: ./contrib/wasm.sh NoStd: # 1 job, run no-std test from script. name: no-std - nightly toolchain